【发布时间】:2011-09-18 21:37:36
【问题描述】:
我喜欢提供有用的错误/消息,我也想为我的static_asserts 这样做。问题是,它们依赖于模板参数。通常,由于引发的错误,这些参数将在途中或其他地方显示,但它们要么是模糊的,要么没有分组,因此它们是有意义的。示例:
template<class T>
struct fake_dependency{
static bool const value = false;
};
template<class T, class Tag>
struct Foo{
Foo(){}
template<class OtherTag>
Foo(Foo<T, OtherTag> const&){
static_assert(fake_dependency<T>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
}
};
int main(){
Foo<int, struct TagA> fA;
Foo<int, struct TagB> fB(fA);
}
MSVC 上的输出:
src\main.cpp(74): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
src\main.cpp(84) : see reference to function template instantiation 'Foo<T,Tag>::Foo<main::TagA>(const Foo<T,main::TagA> &)' being compiled
with
[
T=int,
Tag=main::TagB
]
一个标签在函数模板本身中被提及,另一个在下面的类模板中。不太好。让我们看看GCC outputs:
prog.cpp: In constructor 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]':
prog.cpp:18:32: instantiated from here
prog.cpp:12:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."
好多了,但仍然不是static_assert 所在的位置。现在想象一些更多的参数,或更多的模板,或两者兼而有之。 颤抖
解决这个问题的一种方法是使用中间结构,它将两个标签都作为模板参数:
template<class Tag, class OtherTag>
struct static_Foo_assert{
static_assert(fake_dependency<Tag>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
};
template<class T, class Tag>
struct Foo{
Foo(){}
template<class OtherTag>
Foo(Foo<T, OtherTag> const&){
static_Foo_assert<Tag, OtherTag> x;
}
};
现在让我们再次查看输出:
src\main.cpp(70): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
src\main.cpp(79) : see reference to class template instantiation 'static_Foo_assert<Tag,OtherTag>' being compiled
with
[
Tag=main::TagB,
OtherTag=main::TagA
]
好多了!这是GCC says:
prog.cpp: In instantiation of 'static_Foo_assert<main()::TagB, main()::TagA>':
prog.cpp:17:40: instantiated from 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]'
prog.cpp:23:32: instantiated from here
prog.cpp:8:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."
看起来不错。问题:我需要为每个模板创建这样一个结构,因为static_assert 中的错误消息需要是字符串文字...
现在,对于我的问题:我们能否以某种方式将类型名称直接包含到 static_assert 中?喜欢
static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");
示例输出:
无法从
Foo<int,main::TagB>创建Foo<int,main::TagA>。
或者,如果这无法实现,我们能否以某种方式使错误消息成为一个额外的模板参数,以使其可以通过?
【问题讨论】:
-
我希望看到编译器在这里变得更好。必须可以显示失败的条件。它可以说
note: in static_assert check for fake_dependency<T>::value [with T = ...](在括号中,它枚举了表达式中使用的所有模板参数)。让我们充满希望! -
@Johannes:我认为这可以用
constexpr表达式模板来完成,你不觉得吗?就像您已经可以像 Check 单元测试框架那样反汇编运行时表达式/条件。 -
太糟糕的概念没有融入 C++0x,这将大大减少需求,因为它代表
typeid或dyanamic_cast是确定类型的唯一方法,并且都需要一个实例没有模板参数。 -
@AJ:实际上,
typeid运算符仅对类型完全有效:例如typeid(int)。但问题是,static_assert想要一个文字字符串。 :( -
你提前知道你所有的类型吗?如果是这样,您可以为每种类型创建一个带有特化的错误模板。
标签: c++ templates c++11 custom-errors static-assert