joh*_*dav 5 c++ opengl templates function-pointers c++17
我目前正在使用标准¹C ++ 17中的OpenGl开发RAII系统,同时大量使用模板。现在,我正在研究的系统部分是通过一个通用模板来绑定和解除绑定各种OpenGl对象,然后使用声明为每种类型创建简单的别名。以下是我的头文件的相关摘录,演示了一般技术:
template<typename T, void *bind, void *unbind, typename ... Args>
class RaiiGlBinding{
public:
explicit RaiiGlBinding(const T &t, Args... args) : m_unbindArgs(std::make_tuple(t, args...)) { bind(t, args...); }
~RaiiGlBinding() { if(m_isDestructable) std::apply(unbind_typed, m_unbindArgs); }
private:
static constexpr auto bind_Vaotyped = static_cast<void (*)(T, Args...)>(bind);
static constexpr auto unbind_typed = static_cast<void (*)(T, Args...)>(unbind);
bool m_isDestructable = true;
std::tuple<T, Args...> m_unbindArgs;
};
Vao
namespace glraiidetail{
inline void bindBuffer(GLuint buffer, GLenum target) { glBindBuffer(target, buffer); }
inline void unbindBUffer(GLuint buffer, GLenum target) { glBindBuffer(target, 0); }
}
using RaiiBufferBinding = RaiiGlBinding<GLuint, &glraiidetail::bindBuffer, &glraiidetail::unbindBuffer>;
Run Code Online (Sandbox Code Playgroud)
当我第一次尝试此类时,我在template<>声明(例如template<typename ... Args, void (*)(Args...)>)中使用了非空指针,但这引起了问题,因为1)手动指定更困难Args,2)CLion告诉我可变参数必须为最后。
然后,我将可变参数的论点移到最后,解决了两个问题。但是,这阻止了函数参数访问参数包以进行解包。
为了解决此问题,我将模板参数指针设置为void,然后将其强制转换为类主体中更有用的类型,在该类主体中,函数的地址和参数包均可用。由于我对函数指针的理解与常规指针没有什么不同,除了它们的地址指向所讨论函数的机器代码之外,我认为使用此方法除了轻度损害类型安全性²之外没有其他问题。
不幸的是,当我的编译器不允许我将函数指针void*显式转换为,或以其他方式转换时,这被证明是错误的。经过一些研究,我得出的结论是,我以前对void指针的明显解决方案并不是很多解决方案,因为void*在C ++中将函数指针强制转换为实际上是未定义的行为。
我不能使用函子,因为我希望类的用户能够通过我的using声明甚至不知道它是一个模板类,但函子将需要它的每个实例化来传递的实例。函子类型。
因此,我问非常聪明的堆栈溢出人员:如何解决此问题?
1:这意味着我强烈反对任何可能会起作用的不确定行为,因为可移植性对我很重要。2:尽管强制类型转换本身是不安全的,但是在实例化模板(因此强制类型转换)时,如果出现任何问题,编译器应停止生成错误的编译。因为我打算让代码的用户仅通过using声明使用它,所以这种可能的密码错误是一个非常小的问题。
由于您使用的是C ++ 17,因此只能使用auto模板参数。您可以在类主体中添加静态断言,以确保参数实际上是函数指针。
template <typename T, auto bind, auto unbind, typename... Args>
class RaiiGlBinding {
public:
explicit RaiiGlBinding(const T &t, Args... args)
: m_unbindArgs(std::make_tuple(t, args...)) {
bind(t, args...);
}
~RaiiGlBinding() {
if (m_isDestructable)
std::apply(unbind, m_unbindArgs);
}
private:
bool m_isDestructable = true;
std::tuple<T, Args...> m_unbindArgs;
};
namespace glraiidetail {
inline void bindBuffer(GLuint buffer, GLenum target) {
glBindBuffer(target, buffer);
}
inline void unbindBuffer(GLuint buffer, GLenum target) {
glBindBuffer(target, 0);
}
} // namespace glraiidetail
using RaiiBufferBinding = RaiiGlBinding<GLuint, &glraiidetail::bindBuffer,
&glraiidetail::unbindBuffer>;
Run Code Online (Sandbox Code Playgroud)