Naw*_*waz 9 c++ templates diagnostics static-assert c++11
在模板编程中,static_assert帮助程序员检查模板参数上的约束,并在违反约束时生成人类可读的错误消息.
考虑一下这段代码
template<typename T>
void f(T)
{
static_assert(T(), "first requirement failed to meet.");
static_assert(T::value, "second requirement failed to meet.");
T t = 10; //even this may generate error!
}
Run Code Online (Sandbox Code Playgroud)
我的想法是:如果第一个static_assert失败,这意味着一些要求T不符合,因此编译应该停止,只生成第一个错误消息 - 因为继续编译只是为了生成越来越多的没有多大意义错误消息,其中大多数通常指向单个约束违规.数以百计的错误信息,而不是仅仅一个,看起来很吓人的屏幕上-我甚至可以说,这违背十分目的的static_assert在一定程度上.
例如,如果我将上述函数模板调用为:
f(std::false_type{});
Run Code Online (Sandbox Code Playgroud)
GCC 4.8生成以下内容:
main.cpp: In instantiation of 'void f(T) [with T = std::integral_constant<bool, false>]':
main.cpp:16:24: required from here
main.cpp:7:5: error: static assertion failed: first requirement failed to meet.
static_assert(T(), "first requirement failed to meet.");
^
main.cpp:9:5: error: static assertion failed: second requirement failed to meet.
static_assert(T::value, "second requirement failed to meet.");
^
main.cpp:11:11: error: conversion from 'int' to non-scalar type 'std::integral_constant<bool, false>' requested
T t = 10; //even this may generate error!
Run Code Online (Sandbox Code Playgroud)
正如您所看到的(在线),这是错误的.如果第一个static_assert失败,如果编译继续,很可能其余代码也将失败,那么为什么继续编译呢?在模板编程中,我确信很多程序员不需要这样的级联错误消息!
我试图通过将函数分成多个函数来解决这个问题,每个函数只检查一个约束,如下所示:
template<typename T>
void f_impl(T); //forward declaration
template<typename T>
void f(T)
{
static_assert(T(), "first requirement failed to meet.");
f_impl(T());
}
template<typename T>
void f_impl(T)
{
static_assert(T::value, "second requirement failed to meet.");
T t = 10;
}
f(std::false_type{}); //call
Run Code Online (Sandbox Code Playgroud)
现在生成这个:
main.cpp: In instantiation of 'void f(T) [with T = std::integral_constant<bool, false>]':
main.cpp:24:24: required from here
main.cpp:10:5: error: static assertion failed: first requirement failed to meet.
static_assert(T(), "first requirement failed to meet.");
^
Run Code Online (Sandbox Code Playgroud)
这是一个很大的改进 - 只有一个错误信息更容易阅读和理解(见在线).
我的问题是,
static_assert?我同意 David Rodr\xc3\xadguez 的观点 - dribeas 并为编译器编写者辩护,考虑这个例子:
\n\n#include <type_traits>\n\nclass A {};\n\n// I want the nice error message below in several functions.\n// Instead of repeating myself, let\'s put it in a function.\ntemplate <typename U>\nvoid check() {\n static_assert(std::is_convertible<U*, const volatile A*>::value,\n "U doesn\'t derive publicly from A "\n "(did you forget to include it\'s header file?)");\n}\n\ntemplate <typename U>\nvoid f(U* u) {\n // check legality (with a nice error message)\n check<U>();\n // before trying a failing initialization:\n A* p = u;\n}\n\nclass B; // I forget to include "B.h"\n\nint main() {\n B* b = nullptr;\n f(b);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当实例化f<B>启动时,编译器(或编译器编写者)可能会想:“嗯……我需要实例化check<U>,但人们总是抱怨编译模板太慢了。所以我会继续下去,也许有什么东西下面错误,我不需要实例化check。”
我相信上面的推理是有道理的。(请注意,我不是编译器编写者,所以我只是在这里推测)。
\n\nGCC 4.8和VS2010都继续编译f<B>,推迟实例化check<B>以供稍后使用。然后他们找到失败的初始化并提供自己的错误消息。VS2010 立即停止,我没有收到漂亮的错误消息!GCC 继续前进并产生我想要的消息(但只有在它自己的消息之后)。
元编程对于程序员和编译器来说都是很棘手的。有很大static_assert帮助,但它不是万能药。
| 归档时间: |
|
| 查看次数: |
994 次 |
| 最近记录: |