在 static_assert 输出中集成类型名称?
我喜欢提供有用的错误/消息,并且我也想为我的 static_assert
这样做。问题是,它们依赖于模板参数。通常,由于引发的错误,这些参数将显示在路上或其他地方,但它们要么是模糊的,要么是没有分组的,因此它们是有意义的。示例:
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 输出:
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 所说的:
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
创建Foo
。
或者,如果这无法实现,我们是否可以以某种方式将错误消息作为额外的模板参数,以使其可以通过?
I like to give helpful errors / messages, and I also want to do so for my static_assert
s. The problem is, that they depend on template parameters. Normally, those parameters will get displayed on way or an other due to the error raised, but they are either obscure or not grouped so they make sense. Example:
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);
}
Output on 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
]
One tag is mentioned in the function template itself, the other below with the class template. Not so nice. Lets see what 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>."
Much better, but still not really where the static_assert
is. And now imagine some more parameters, or more templates, or both. shivers
One way to work around that is to use an intermediate struct, which takes both Tags as template parameters:
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;
}
};
Now lets see the output again:
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
]
Much better! Here's what 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>."
Looks not bad. The problem: I need to create such a struct for every template, since the error message in static_assert
needs to be a string literal...
Now, for my question: Can we somehow include the type names directly into the static_assert
? Like
static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");
Example output:
Cannot create
Foo<int,main::TagA>
fromFoo<int,main::TagB>
.
Or, if that isn't achievable, can we somehow make the error message an extra template parameter, as to make it passable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我的黑客
代码:
它允许您检查任何
::value
断言并在失败时转储类型。用法:
其中
std::my_check<...>::value
是检查的布尔结果示例
对于完整的 SSCCE< /a> 示例参见: IDEOne 示例
示例的错误消息:
Explanation
如果断言失败,它将打印 AssertValue 的模板参数,因此打印完整的模板扩展你的支票。例如,如果您正在检查
std::is_base_of
,它将打印检查的完整类型,例如:std::is_base_of
。然后您就可以确切地知道失败的断言中使用了哪些类型。唯一的问题是,这仅适用于将结果放入
::value
的模板。然而type_traits
主要使用这个并且是 goto 标准。My Hack
Code:
It allows for you to check any
::value
assertion and dump the types if it failed.Usage:
where
std::my_check<...>::value
is the boolean result of the checkExample
For a full SSCCE example see: IDEOne Example
The Example's error message:
Explanation
If the assertion fails, it will print the template arguments of AssertValue and therefore print the full template expansion of your check. For example, if you were checking a
std::is_base_of
it will print the full type of the check, e.g.:std::is_base_of<IMyInterface, MyBadType>
. Then you know exactly what types were used in the failed assertion.The only problem is that this only works on templates that put their result in
::value
. Howevertype_traits
mostly uses this and is the goto standard.如果您的编译器提供了 __FUNCTION__ 宏,您可以使用它和文字连接进行非常简单的替换。但是,gcc 和 clang 的实现不是作为宏完成的,因此该解决方案对它们不起作用。
由 VS2015 编译时会产生以下输出:
If your compiler provides the
__FUNCTION__
macro, you can have a really simple substitution using it and literal concatenation. However, gcc's and clang's implementation is not done as a macro, so this solution will not work for them.This produces the following output when compiled by VS2015:
可以获取作为模板非类型参数传入的字符串文字,并带有一点 hoop-jumping 。但由于
static_assert
的第二个参数被限制为字符串文字,而不是地址常量表达式,不幸的是,这没有多大用处。可悲的是,我怀疑您最好的选择是游说委员会或编译器编写者扩展该设施。
It's possible to get a string literal passed in as a template non-type parameter, with a little bit of hoop-jumping. But since the second argument to
static_assert
is constrained to be a string literal rather than, say, an address constant expression, this unfortunately is not much use.Sadly I suspect your best bet is to lobby the committee or the compiler writers to extend the facility.
__FUNCSIG__
包括 MSVC 上的模板参数,以及 GCC 上的__PRETTY_FUNCTION__
。请注意,
__func__
和__FUNCTION__
并不总是包含模板参数。__FUNCSIG__
includes the template arguments on MSVC, and__PRETTY_FUNCTION__
for GCC.Note that
__func__
and__FUNCTION__
do not always include template arguments.我看到不久前已经回答了这个问题,但完整的答案丢失了,我找到了一种非常简单的方法来达到预期的结果。
如果 value=true,该函数将编译并且无效,否则我们会收到以下错误消息:
如果我们想要更通用一点,我们可以将其放入宏中
I see this has been answered a while ago, but the full answer was lost, and I found a very simply way to achieve the desired result.
This function will compile and have no effect if value=true, otherwise we get this error message:
If we wanna be a bit more general we can put it in a macro