Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if function is declared in global scope at compile time

Let I have a header, for example #include <GL/gl.h>. It contains subset of OpenGL API functions. I need something like this:

static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect");

Or even better:

PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr;

Where ptr_to_glDrawArraysIndirect::ptr unrolls to pointer to glDrawArraysIndirect if it's defined or to a stub function stub_glDrawArraysIndirect otherwise.

My target operating system is very specific. Any linker based solution (like GetProcAddress or dlsym) doesn't work for me, since there is no dynamic linker. More than, my driver doesn't provide glXGetProcAdrress nor wglGetProcAddress, basically there there is no way to query pointer at run time by function name (Actually, I want to implement such a mechanism).

Any ideas?

like image 326
ivaigult Avatar asked Mar 11 '16 15:03

ivaigult


Video Answer


1 Answers

Here is an answer that can detect it at compile time and produce a boolean value. It works by creating a template function of the same name in a namespace and then using that namespace inside of the is_defined() function. If the real glDrawArraysIndirect() exists it will take preference over the template version. If you comment out the first declaration of glDrawArraysIndirect() the static assert at the bottom will trigger.

Test on GodBolt

#include <type_traits>

enum GLenum {};

void glDrawArraysIndirect(GLenum, const void*);

namespace detail {
    struct dummy;

    template<typename T>
    dummy& glDrawArraysIndirect(T, const void*);
}

constexpr bool is_defined()
{
    using namespace detail;
    using ftype = decltype(glDrawArraysIndirect(GLenum(), nullptr));
    return std::is_same<ftype, void>();
}

static_assert(is_defined(), "not defined");

With a little tweak you can make your custom function the template and use a similar trick

ideone.com

#include <type_traits>
#include <iostream>

//#define USE_REAL

enum GLenum {TEST};

typedef void (*func_type)(GLenum, const void*);

#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*);
#endif

namespace detail {
    struct dummy {};

    template<typename T = dummy>
    void glDrawArraysIndirect(GLenum, const void*, T = T())
    {
        std::cout << "In placeholder function" << std::endl;
    }

}

void wrapDraw(GLenum x, const void* y)
{
  using namespace detail;
  glDrawArraysIndirect(x, y);
}

#ifdef USE_REAL
void glDrawArraysIndirect(GLenum, const void*)
{
    std::cout << "In real function" << std::endl;
}
#endif

int main()
{
    wrapDraw(TEST, nullptr);
}
like image 145
Kurt Stutsman Avatar answered Nov 14 '22 05:11

Kurt Stutsman