如何在编译时检查函数是否在全局范围内声明

iva*_*ult 5 c++ opengl templates

例如,让我有一个标题#include <GL/gl.h>.它包含OpenGL API函数的子集.我需要这样的东西:

static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect");
Run Code Online (Sandbox Code Playgroud)

甚至更好:

PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr;
Run Code Online (Sandbox Code Playgroud)

ptr_to_glDrawArraysIndirect::ptr解开,如果它的定义或存根函数指针glDrawArraysIndirect stub_glDrawArraysIndirect否则.

我的目标操作系统非常具体.任何基于链接器的解决方案(如GetProcAddressdlsym)对我都不起作用,因为没有动态链接器.不止,我的驱动程序没有提供glXGetProcAdrress也没有wglGetProcAddress,基本上没有办法在运行时通过函数名查询指针(实际上,我想实现这样的机制).

有任何想法吗?

Kur*_*man 6

这是一个可以在编译时检测它并产生一个布尔值的答案.它的工作原理是在命名空间中创建同名的模板函数,然后在is_defined()函数内部使用该命名空间.如果真实glDrawArraysIndirect()存在,它将优先于模板版本.如果你注释掉glDrawArraysIndirect()底部的静态断言的第一个声明将触发.

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");
Run Code Online (Sandbox Code Playgroud)

通过一些调整,您可以将自定义功能作为模板并使用类似的技巧

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);
}
Run Code Online (Sandbox Code Playgroud)