Мне нравится давать полезные сообщения об ошибках, и я также хочу сделать это для моих static_assert
s.Проблема в том, что они зависят от параметров шаблона.Обычно эти параметры отображаются в пути или по другому из-за возникшей ошибки, но они либо неясны, либо не сгруппированы, поэтому имеют смысл.Пример:
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
.А теперь представьте еще несколько параметров, или больше шаблонов, или оба. shivers
Один из способов обойти это - использовать промежуточную структуру, которая принимает оба тега в качестве параметров шаблона:
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<int,main::TagA>
из Foo<int,main::TagB>
.
Или, если это невозможно,можем ли мы как-то сделать сообщение об ошибке дополнительным параметром шаблона, чтобы сделать его проходимым?