I like to give useful errors / messages and I also want to do this for my static_assert s. The problem is that they depend on the template options. Typically, these parameters will be displayed one way or another due to an error, but they are either unclear 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 to 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, and the other below with the class template. Not very nice. Let's see what the GCC Outputs are :
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 where the static_assert . Now imagine a few more options, or more templates, or both. goosebumps
One way around this is to use an intermediate structure that accepts 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 look again at the exit:
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 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 good. Problem: I need to create such a structure for each template, since the error message in static_assert should be a string literal ...
Now, in my question: can we somehow include type names directly in static_assert ? how
static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");
Output Example:
Cannot create Foo<int,main::TagA> from Foo<int,main::TagB> .
Or, if this is not possible, can we somehow make the error message an additional template parameter to make it available?