【问题标题】:How do I embed a type's name as a string into a static_assert()? [duplicate]如何将类型名称作为字符串嵌入到 static_assert() 中? [复制]
【发布时间】:2014-01-03 11:54:08
【问题描述】:

问题

由于消息不是字符串文字,因此无法构建以下内容。

template<typename T>
struct Foo
{ 
  Foo() 
  {
    static_assert( is_pod<T>::value, typeid(T).name() );
  }
};

最终,如果我尝试编译 Foo&lt;Bar&gt; fb;,我想要一条失败消息,例如“Bar 必须是 pod 类型”。

是否可以按照static_assert 的要求在编译时构建此字符串?

【问题讨论】:

  • 在编译时编译一个字符串——你应该能够用一些肮脏的宏技巧或模板魔法来做到这一点。 See here 类似的东西。

标签: c++ templates c++11 typeid static-assert


【解决方案1】:

不可能在编译时构建所需的字符串并将其放入消息中,但这在实践中通常不是问题,因为错误消息将包含调用上下文,您始终可以为您的 @ 创建一个包装器987654323@ 显示错误信息中的类型:

template< typename T >
void verify_pod()
{
    static_assert( std::is_pod<T>::value, "T is not a POD" );
}

产量

clang++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:7:5: error: static_assert failed "T is not a POD"
    static_assert( std::is_pod<T>::value, "T is not a POD" );
    ^              ~~~~~~~~~~~~~~~~~~~~~
main.cpp:12:5: note: in instantiation of function template specialization 'verify_pod<std::basic_string<char> >' requested here
    verify_pod< std::string >();
    ^
1 error generated.

注意note: ...,其中显示了类型为std::string(或此处:std::basic_string&lt;char&gt;)的包装器。

Live example (Clang)

对于GCC,报错信息也很nice:

main.cpp: In instantiation of 'void verify_pod() [with T = std::basic_string<char>]':
main.cpp:12:31:   required from here
main.cpp:7:5: error: static assertion failed: T is not a POD
     static_assert( std::is_pod<T>::value, "T is not a POD" );
     ^

Live example (GCC)

【讨论】:

  • 请注意,g++ 可能不会产生如此好的错误消息。
  • @arne 不正确。实际上,GCC 的错误信息更好(恕我直言)。
  • 对于漂亮的错误消息,我们似乎有非常不同的想法。在您的情况下,它可能看起来不错,但如果您有很多模板内容,g++ 的输出实际上变得难以阅读恕我直言。不过你的答案是正确的。
  • 我不知道,与我见过的一些非常丑陋的错误消息相比,这对我来说看起来相当不错。 :)
【解决方案2】:

在模板中,您会看到 Daniel Freyexplained。在模板之外,单独使用 static_assert 是不可能的,但可以在宏和字符串化运算符 # 的帮助下完成:

#define VERIFY_POD(T) \
    static_assert(std::is_pod<T>::value, #T " must be a pod-type" );

对于带有 gcc 4.8.1 的 struct non_pod { virtual ~non_pod() {} }; 类型,VERIFY_POD(non_pod) 给出

main.cpp:4:2: error: static assertion failed: non_pod must be a pod-type
  static_assert(std::is_pod<T>::value, #T " must be a pod-type" );
  ^
main.cpp:15:2: note: in expansion of macro 'VERIFY_POD'
  VERIFY_POD(non_pod);

如果您和我一样不想在错误消息中看到标记 #T " must be a pod-type",那么您可以在宏定义中添加额外的一行:

#define VERIFY_POD(T) \
    static_assert(std::is_pod<T>::value, \
    #T "must be a pod-type" );

有了这个,前面的例子产生:

main.cpp: In function 'int main()':
main.cpp:4:2: error: static assertion failed: non_pod must be a pod-type
  static_assert(std::is_pod<T>::value, \
  ^
main.cpp:14:2: note: in expansion of macro 'VERIFY_POD'
  VERIFY_POD(non_pod);
  ^

当然,错误消息的确切外观取决于编译器。使用 clang 3.4 我们得到

main.cpp:14:5: error: static_assert failed "non_pod must be a pod-type"
    VERIFY_POD(non_pod);
    ^~~~~~~~~~~~~~~~~~~

main.cpp:3:23: note: expanded from macro 'VERIFY_POD'
#define VERIFY_POD(T) \
                      ^
1 error generated.

【讨论】:

  • 我不认为这可以像在 OP 中那样使用模板。我的意思是,如果我没记错的话,它会输出模板参数的名称。
  • @DyP 实际上,这在模板之外效果更好。在模板内部,它的“工作方式”与Daniel Freyanswer 相同。
  • @DyP 我更新了帖子以澄清这一点。谢谢。
  • “在模板之外,单独使用 static_assert 是不可能的” 它与模板内部一样有效;)您的解决方案确实更好 外部模板,而不仅仅是使用 static_assert,为此 +1。
  • 我认为您可以只打印作为参数写入的内容,但请注意,这正是您在static_assert 中输入的内容是第一个参数。如果静态断言失败,这一行,包括你写的内容都会打印在错误消息中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多