Tar*_*Tar 11 c++ static-assert
假设我有一个模板函数,它接受一个整数和一个const引用到类型为T的实例.现在,根据整数,只有一些T是可加入的,否则在运行时抛出异常.
如果此函数的所有使用都使用常量整数,则可以使int成为模板参数并使用静态断言来检查它是否可接受.因此,func(1,c)不会使用func<1>(c)并将获得编译时类型检查.有没有办法编写func(1,c)并仍然保持编译时检查,同时还能够编写func(i,c)和使用动态断言?目标是使其对开发人员透明.添加这种安全性而不打扰开发人员关于编译时常量之类的东西会很棒.他们可能只记得func(1,c)总是有效并且使用它,避免检查.
如何尽可能使用静态断言定义函数,否则动态断言?
以下代码显示了Ivan Shcherbakov的 GCC解决方案:
#include <iostream>
#include <cassert>
template<typename T>
void __attribute__((always_inline)) func(const int& i, const T& t);
void compile_time_error_() __attribute__((__error__ ("assertion failed")));
template<>
void __attribute__((always_inline))
func(const int& i, const float& t)
{
do {
if (i != 0) {
if (__builtin_constant_p(i)) compile_time_error_();
std::cerr << "assertion xzy failed" << std::endl;
exit(1);
}
} while (0);
func_impl<float>(i,t);
}
Run Code Online (Sandbox Code Playgroud)
这只允许i = 0和T = float的组合.对于其他组合,一个好方法是创建一个宏,生成代码为template<> func(const int& i, const T& t)T,并且i!= 0被替换.
好吧,如果你正在使用GCC,你可以使用脏黑客,但只有在启用了函数内联(-O1或更多)时它才会起作用:
void my_error() __attribute__((__error__ ("Your message here")));
template <typename T1, typename T2> struct compare_types
{
enum {Equals = 0};
};
template <typename T1> struct compare_types<T1,T1>
{
enum {Equals = 1};
};
template <typename Type> __attribute__((always_inline)) void func(int a, Type &x)
{
if (__builtin_constant_p(a))
{
if (a == 1 && compare_types<Type,char>::Equals)
my_error();
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,当a == 1和Type是char,你会得到一个错误.这是一个触发它的例子:
int main()
{
char x;
func(1, x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,此示例严重依赖于特定于gcc的__builtin_constant_p()函数,并且不能与其他编译器一起使用!