Интегрировать имя типа в вывод static_assert?

Я люблю выдавать полезные ошибки / сообщения, и я также хочу сделать это для моих 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 .

Или, если это невозможно, можем ли мы каким-то образом сделать сообщение об ошибке дополнительным параметром шаблона, чтобы сделать его приемлемым?

54
задан Xeo 5 October 2012 в 07:38
поделиться