問題描述
我喜歡提供有用的錯誤/消息,我也想為我的 static_assert
這樣做.問題是,它們依賴于模板參數.通常,由于引發的錯誤,這些參數會在途中或其他地方顯示,但它們要么模糊不清,要么沒有分組,因此它們是有意義的.示例:
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);
}
MSVC 上的輸出:
srcmain.cpp(74): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
srcmain.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 輸出:
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>."
好多了,但仍然不是 static_assert
所在的位置.現在想象更多的參數,或更多的模板,或兩者兼而有之.顫抖
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:
srcmain.cpp(70): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
srcmain.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
中的錯誤消息需要是字符串文字...
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...
現在,對于我的問題:我們能否以某種方式將類型名稱直接包含在 static_assert
中?喜歡
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 ">.");
示例輸出:
無法從 Foo
創建 Foo
.
或者,如果這無法實現,我們能否以某種方式使錯誤消息成為額外的模板參數,以使其可通過?
Or, if that isn't achievable, can we somehow make the error message an extra template parameter, as to make it passable?
推薦答案
My Hack
代碼:
template <typename Assertion>
struct AssertValue : AssertionChecker<Assertion::value, Assertion>
{
static_assert(AssertionValue, "Assertion failed <see below for more information>");
static bool const value = Assertion::value;
};
它允許您檢查任何 ::value
斷言并在失敗時轉儲類型.
It allows for you to check any ::value
assertion and dump the types if it failed.
// Bad indentation used to show parts
static_assert(
AssertValue<
std::my_check<
T0, decltype(*somethingComplicated), T7::value_type
>
>,
"something horrible happened"
);
其中 std::my_check<...>::value
是檢查的布爾結果
where std::my_check<...>::value
is the boolean result of the check
有關完整的 SSCCE 示例,請參閱:IDEOne 示例
For a full SSCCE example see: IDEOne Example
示例的錯誤信息:
prog.cpp: In instantiation of 'AssertValue<std::is_base_of<IMyInterface, MyBadType> >':
prog.cpp:37:69: instantiated from 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]'
prog.cpp:60:38: instantiated from here
prog.cpp:9:5: error: static assertion failed: "Assertion failed <see below for more information>"
prog.cpp: In function 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]':
prog.cpp:60:38: instantiated from here
prog.cpp:39:5: error: static assertion failed: "iterator passed does not reference IMyInterface items"
說明
如果斷言失敗,它將打印 AssertValue 的模板參數,因此打印您支票的完整模板擴展.例如,如果您正在檢查 std::is_base_of
,它將打印檢查的完整類型,例如:std::is_base_of
.然后你就知道在失敗的斷言中使用了哪些類型.
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.
唯一的問題是這只適用于將結果放在 ::value
中的模板.然而,type_traits
主要使用這個并且是 goto 標準.
The only problem is that this only works on templates that put their result in ::value
. However type_traits
mostly uses this and is the goto standard.
這篇關于在 static_assert 輸出中集成類型名稱?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!