在模板编程中,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!
}
我的想法是:如果第一次static_assert
失败,这意味着不满足某些要求,因此编译应该停止,只生成第一条错误消息——因为继续编译只是为了生成越来越多的信息没有多大意义错误消息,其中大多数通常指向单个约束违规。数百条错误消息,而不仅仅是一条,在屏幕上看起来非常可怕——我什至会说,它在某种程度上违背了它的目的。T
static_assert
例如,如果我将上述函数模板称为:
f(std::false_type{});
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!
正如你所看到的(在线),这是太多的错误。如果第一个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
现在这会生成:
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.");
^
这是一个很大的改进——只有一条错误消息更容易阅读和理解(参见在线)。
我的问题是,
- 为什么编译不会停在第一个
static_assert
? - 由于拆分函数模板并检查每个 function_impl 中的一个约束,仅有助于GCC 和 clang仍然会 产生大量错误,有没有办法以更一致的方式改进诊断——适用于所有编译器的东西?