假设我有一个模板函数,它使用一个整数和一个const类型的引用.现在根据整数,只有一些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); }
这将仅允许i = 0和T = float的组合.对于其他组合,一个好的方法是创建一个生成模板代码的宏,更换T和i!= 0的func(const int& i,const T& t)
解决方法
那么,如果你使用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(); } }
在这种情况下,当一个== 1和Type是char时,你会得到一个错误.这是一个会触发它的例子:
int main() { char x; func(1,x); return 0; }
请注意,此示例严重依赖于gcc特定的__builtin_constant_p()函数,并且不能与其他编译器一起使用!