我有一个标题,例如#include <GL/gl.h>
。它包含OpenGL API函数的子集。我需要这样的东西:
static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect");
甚至更好:
PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr;
其中ptr_to_glDrawArraysIndirect::ptr
展开指向glDrawArraysIndirect(如果已定义),或者指向存根函数stub_glDrawArraysIndirect
。
我的目标操作系统非常具体。任何基于链接器的解决方案(如GetProcAddress
或dlsym
)对我都不起作用,因为没有动态链接器。不仅如此,我的驱动程序还没有提供glXGetProcAdrress
或wglGetProcAddress
,基本上没有办法在运行时通过函数名查询指针(实际上,我想实现这样的机制)。
有什么想法吗?
答案 0 :(得分:6)
这是一个可以在编译时检测它并产生一个布尔值的答案。它的工作原理是在命名空间中创建同名的模板函数,然后在is_defined()
函数内使用该命名空间。如果真实的glDrawArraysIndirect()
存在,它将优先于模板版本。如果你注释掉glDrawArraysIndirect()
的第一个声明,那么底部的静态断言就会触发。
#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");
通过一些调整,您可以将自定义功能作为模板并使用类似的技巧
#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);
}
答案 1 :(得分:3)
在某处包含表达式sizeof(::function)
。 (如果函数存在,那么询问函数指针的大小是完全有效的事情)。
在运行时它是良性的,::
强制使用在全局范围内声明的function
。
当然,如果全局范围内不存在function
,则编译将失败。
除了其他错误之外,如果要在
行上写一些内容,编译器将发出特定错误 static_assert(sizeof(::function), "There is no global function");
答案 2 :(得分:1)
我的目标操作系统非常具体。任何基于链接器的解决方案(如GetProcAddress或dlsym)对我都不起作用,因为没有动态链接器。
这是一个嵌入式系统还是只是在标准PC硬件上运行的奇怪的操作系统?
不仅如此,我的驱动程序还没有提供glXGetProcAdrress和wglGetProcAddress,基本上没有办法在运行时通过函数名查询指针
在运行时查询函数指针的依赖性不依赖于动态链接器的存在。这两个是完全正交的,甚至纯粹静态链接的嵌入式OpenGL实现也可以提供GetProcAddress
接口。我不是试图以某种方式在编译或链接时解决问题,而是通过为您的OpenGL驱动程序实现GetProcAddress
来解决问题;即使驱动程序仅作为二进制形式的静态库可用,也可以这样做。第一步:
为每个OpenGL函数创建函数指针存根,静态初始化为NULL并归因于弱链接。将其链接到静态库,您可以调用gl_null_stubs
或类似的。
创建一个GetProcAddress
函数,对于每个OpenGL函数,返回指向函数编译单元范围内的函数符号的指针。
现在将您奇怪的OpenGL驱动程序与存根库和GetProcAddress
实现链接起来。对于每个函数,存根的弱连接将静态库符号优先。对于驱动程序中没有的所有OpenGL符号,存根将接管。
那里:现在你有一个具有 GetProcAddress实现的OpenGL驱动程序库。那不是那么难,是吗?
答案 3 :(得分:1)