基于模板的编译时断言与自定义消息只能在某些编译器中编译

时间:2013-07-25 14:21:55

标签: c++ templates visual-c++ gcc icc

此代码使用模板演示编译时断言。 我发现它只能用g ++(4.4.7)编译,并带有以下cmd行。

$ g++ -std=c++98 a.cpp -o a

Nether icc(13.0.1)和visual c ++(80x86的14.00.50727.762)都可以编译它。对于icc,它会像这样生成错误消息

$ icpc a.cpp -o a
a.cpp(13): error: non-integral operation not allowed in nontype template argument
      COMPILE_TIME_ASSERT(true && "err msg");
      ^

a.cpp(13): error: class "CompileTimeAssert<<error-constant>>" has no member "Check"
      COMPILE_TIME_ASSERT(true && "err msg");
      ^

compilation aborted for a.cpp (code 2)

但是我发现像true && "err msg"这样的断言在运行时断言中广泛用作Add custom messages in assert?

问题是

  1. 只有使用正确的编译选项,才能在不修改代码的情况下解决这个问题吗?
  2. 如果不能,编译时的任何替代方法都会使用自定义消息断言?
  3. 演示代码如下所示。

    #include <iostream>
    
    template<bool B> class CompileTimeAssert { };
    template<> class CompileTimeAssert<true> {
     public:
      static inline void Check() { }
    };
    
    #define COMPILE_TIME_ASSERT(b) CompileTimeAssert<(b)>::Check()
    
    int main()
    {
        COMPILE_TIME_ASSERT(true && "err msg");
        std::cout<<(true && "err msg")<<std::endl;
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

对第一个问题的回答是“否”。传递给模板的参数称为“非类型模板参数”。根据标准,这些论点必须是:

  

常量表达式,具有外部链接的函数或对象的地址,或静态类成员的地址。

严格来说,true && "err msg"这样的表达式无法在编译时确定。这就是为什么它可以用于运行时断言,但不能用于编译时断言。 G ++在这里演示了非标准行为。

作为对第二个问题的回答,我提出以下模式:

#define STATIC_ASSERT(e,m) extern char (*__static_assert_failed(void)) [ 1 - 2*!(e) ] 

__static_assert_failed这里是一个指向外部函数的指针,返回一个字符数组。该数组的大小为1 - 2*!(e),如果e为false,则会导致编译时错误。