Фон
Согласно стандарту C++, при объявлении типа шаблона вперед с параметрами шаблона по умолчанию каждый из них может появляться только в одном объявлении. Например:
// GOOD example
template <class T = void>
class Example; // forward-declaration
template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example; // forward-declaration
template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example; // forward-declaration
template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition
проблема
В моем коде много предварительных объявлений в разных файлах, поэтому имеет смысл поместить параметры по умолчанию в определение:
// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};
и, как и ожидалось, все это работает хорошо везде... кроме лязга! Я сузил проблему до этого:
В clang, если шаблон класса имеет параметры по умолчанию, но они не объявлены в первом предварительном объявлении этого класса, и при объявлении экземпляра этого класса угловые скобки не указываются, clang игнорирует параметр по умолчанию и выдает ошибку "нет жизнеспособный конструктор или руководство по выводу для аргументов шаблона... ".
пример
// GOOD example
template <class T>
class Example;
template <class T = void>
class Example {};
int main() {
Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
- Перемещение
= void
в предварительную декларацию устраняет проблему, но не жизнеспособно для меня, поскольку мои forward-decls находятся в разных файлах, и я не знаю, какой из них появится первым. (Также супер проблематично, так как мои значения по умолчанию будут в каком-то непонятном файле глубоко в базе кода) - Изменение
Example e;
кExample<> e;
решает проблему, но не подходит для меня, так как я разработчик библиотеки и не хочу, чтобы все мои пользователи печатали<>
после моих занятий. - Добавление файла предварительного объявления
example_fwd.hpp
с одним предварительным объявлением и включение его вместо прямого объявления каждый раз устраняет проблему, но я хотел бы избежать этого, если есть лучшее решение.
Вопрос
Кто прав в этом случае: Clang или другие компиляторы? Это ошибка компилятора? Как я могу обойти эту проблему (кроме частичных решений, которые я описал выше)? Я нашел # 10147 (и связанные с ним вопросы о стековом потоке), но он касается параметров шаблона шаблона и также помечен как исправленный более года назад.
редактировать
Это похоже на ошибку, и теперь о ней сообщается на трекере ошибок LLVM (# 40488).