Я люблю выдавать полезные ошибки / сообщения, и я также хочу сделать это для моих static_assert
s. Проблема в том, что они зависят от параметров шаблона. Обычно эти параметры будут отображаться по пути или по другому из-за возникшей ошибки, но они либо неясны, либо не сгруппированы, поэтому имеют смысл. Пример:
template
struct fake_dependency{
static bool const value = false;
};
template
struct Foo{
Foo(){}
template
Foo(Foo const&){
static_assert(fake_dependency::value, "Cannot create Foo from Foo.");
}
};
int main(){
Foo fA;
Foo fB(fA);
}
Вывод в MSVC:
src\main.cpp(74): error C2338: Cannot create Foo from Foo.
src\main.cpp(84) : see reference to function template instantiation 'Foo::Foo(const Foo &)' being compiled
with
[
T=int,
Tag=main::TagB
]
Один тег упоминается в самом шаблоне функции, другой ниже - в шаблоне класса. Не очень хорошо. Давайте посмотрим, что GCC выводит :
prog.cpp: In constructor 'Foo::Foo(const Foo&) [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 from Foo."
Намного лучше, но все же не совсем там, где находится static_assert
. А теперь представьте себе еще несколько параметров, или несколько шаблонов, или и то, и другое. shivers
Один из способов обойти это - использовать промежуточную структуру, которая принимает оба тега в качестве параметров шаблона:
template
struct static_Foo_assert{
static_assert(fake_dependency::value, "Cannot create Foo from Foo.");
};
template
struct Foo{
Foo(){}
template
Foo(Foo const&){
static_Foo_assert x;
}
};
Теперь давайте снова посмотрим на результат:
src\main.cpp(70): error C2338: Cannot create Foo from Foo.
src\main.cpp(79) : see reference to class template instantiation 'static_Foo_assert' being compiled
with
[
Tag=main::TagB,
OtherTag=main::TagA
]
Намного лучше! Вот что GCC говорит :
prog.cpp: In instantiation of 'static_Foo_assert':
prog.cpp:17:40: instantiated from 'Foo::Foo(const Foo&) [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 from Foo."
Выглядит неплохо. Проблема: мне нужно создать такую структуру для каждого шаблона, поскольку сообщение об ошибке в static_assert
должно быть строковым литералом ...
Теперь, на мой вопрос: можем ли мы как-то включить тип имена прямо в static_assert
? Как
static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");
Пример вывода:
Невозможно создать
Foo
изFoo
.
Или, если это невозможно, можем ли мы каким-то образом сделать сообщение об ошибке дополнительным параметром шаблона, чтобы сделать его приемлемым?