Search code examples
c++templatesc++11variadic

Debug function wrapper


I use a template function for wrapping OpenGL API calls (for error code catching):

template<typename Function, typename ... Args>
auto __glFunction(const char *file, int line, Function f, Args ...args) -> decltype(f(args...)) {
    auto result = f(args...);
    auto error = glGetError();
    if (error != GL_NO_ERROR) {
        switch(error) {
            case GL_INVALID_ENUM:
                std::cout << "GL_INVALID_ENUM";
                break;
            case GL_INVALID_VALUE:
                std::cout << "GL_INVALID_VALUE";
                break;
            case GL_INVALID_OPERATION:
                std::cout << "GL_INVALID_OPERATION";
                break;
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                std::cout << "GL_INVALID_FRAMEBUFFER_OPERATION";
                break;
            case GL_OUT_OF_MEMORY:
                std::cout << "GL_OUT_OF_MEMORY";
                break;
            case GL_STACK_UNDERFLOW:
                std::cout << "GL_STACK_UNDERFLOW";
                break;
            case GL_STACK_OVERFLOW:
                std::cout << "GL_STACK_OVERFLOW";
                break;
            default:
                std::cout << "GL_ERROR #" << error;
                break;
        }
        std::cout << " at " << file << ":" << line << std::endl;
    }

    return result;
};

#define glFunction(function, ...) __glFunction(__FILE__, __LINE__, function, ##__VA_ARGS__)

It works well with functions which have non-void return type. How should I specify template to work with void-returning functions as well as non-void.


Solution

  • Solution

    May be it will be helpful for someone. Next code works well with both (void / non-void)-returning functions:

    void __glPrintError(const char *file, const int line) {
        auto error = glGetError();
        if (error != GL_NO_ERROR) {
            switch(error) {
                case GL_INVALID_ENUM:
                    std::cout << "GL_INVALID_ENUM";
                    break;
                case GL_INVALID_VALUE:
                    std::cout << "GL_INVALID_VALUE";
                    break;
                case GL_INVALID_OPERATION:
                    std::cout << "GL_INVALID_OPERATION";
                    break;
                case GL_INVALID_FRAMEBUFFER_OPERATION:
                    std::cout << "GL_INVALID_FRAMEBUFFER_OPERATION";
                    break;
                case GL_OUT_OF_MEMORY:
                    std::cout << "GL_OUT_OF_MEMORY";
                    break;
                case GL_STACK_UNDERFLOW:
                    std::cout << "GL_STACK_UNDERFLOW";
                    break;
                case GL_STACK_OVERFLOW:
                    std::cout << "GL_STACK_OVERFLOW";
                    break;
                default:
                    std::cout << "GL_ERROR #" << error;
                    break;
            }
            std::cout << " at " << file << ":" << line << std::endl;
        }
    }
    
    template<typename Function, typename ... Args>
    auto __glFunction(const char *file, const int line, Function f, Args ...args) ->
        typename std::enable_if<!std::is_same<decltype(f(args...)), void>::value, decltype(f(args...))>::type {
    
        auto result = f(args...);
        __glPrintError(file, line);
        return result;
    };
    
    template<typename Function, typename ... Args>
    auto __glFunction(const char *file, const int line, Function f, Args ...args) ->
        typename std::enable_if<std::is_same<decltype(f(args...)), void>::value, decltype(f(args...))>::type {
    
        f(args...);
        __glPrintError(file, line);
    };
    
    #define glFunction(function, ...) __glFunction(__FILE__, __LINE__, function, ##__VA_ARGS__)