#c #templates #g #language-lawyer #clang
#c #шаблоны #g #язык-юрист #clang
Вопрос:
GCC 7.3.1 компилирует приведенный ниже код, в то время как clang 8.0.0 этого не делает. Я хотел бы знать, допустим ли этот синтаксис (в этом случае я сообщу об этом как о возможной ошибке clang).
Спасибо за вашу помощь.
template<typename FOO>
struct Foo
{
using Value = int;
template<Value VALUE>
struct Bar;
};
template<typename FOO>
template<typename Foo<FOO>::Value VALUE>
struct Foo<FOO>::Bar { static void test(); };
template<typename FOO>
template<typename Foo<FOO>::Value VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}
int main() { return 0; }
Сообщение об ошибке с clang выглядит следующим образом:
error: nested name specifier 'Foo<FOO>::Bar<VALUE>::' for declaration does not refer into a class, class template or class template partial specialization
void Foo<FOO>::Bar<VALUE>::test() {}
~~~~~~~~~~~~~~~~~~~~~~^
1 error generated.
Редактировать:
Здесь появляется сообщение о возможной ошибке clang.
Комментарии:
1. Существует несколько основных проблем, связанных с эквивалентностью типов шаблонов и псевдонимами (например, 1979 ). Может быть связано.
Ответ №1:
Из [temp.mem.class/1] мы имеем
Класс-член шаблона класса может быть определен вне определения шаблона класса, в котором он объявлен.
Кроме того, в контексте, отличном от шаблона, [class.nest/2] сообщает нам:
Функции-члены и статические данные вложенного класса могут быть определены в области пространства имен, включающей определение их класса.
Поэтому давайте построим более простой пример и убедимся, что определение функции-члена вложенного типа разрешено отделять от определения самого вложенного, не шаблонного типа. По аналогии с типами в вашем фрагменте:
template <class FOO>
struct Foo {
// Simpler, Bar is not a template
struct Bar;
};
// Definition of Bar outside of Foo as before
template <class FOO>
struct Foo<FOO>::Bar {
static void test();
};
А теперь критическая часть, определение Bar::test()
вне Bar
самого себя:
template <class FOO>
void Foo<FOO>::Bar::test() { }
Это успешно компилируется с обоими gcc-8
и clang
(магистральная, а также гораздо более старая стабильная версия).
Возможно, я здесь что-то недопонимаю, но мой вывод заключается в том, что синтаксис для определения Foo::Bar::test()
вне Foo
и outside of Bar
действительно хорош, и clang
его следует скомпилировать так, как это gcc
делается.
Ответ №2:
Это интересный случай! Моя позиция, будь то проблема с компилятором или стандартная проблема, похожа на @lubgr, но я хотел бы добавить еще несколько идей.
У ICC также есть некоторые проблемы с вашей конструкцией, что может свидетельствовать о том, что это более глубоко укоренено в стандарте (тем не менее, gcc здесь может быть правильным). Сбой с ошибкой: «список аргументов шаблона должен соответствовать списку параметров» — это может означать, что для обоих компиляторов это:
template<typename FOO>
template<typename Foo<FOO>::Value VALUE>
не идентичны исходному определению Foo
. Похоже, это ошибка обоих компиляторов, но я научился быть осторожным, когда два разных компилятора имеют схожие проблемы.
Извлечение определения Value
из исходного шаблона в отдельный устраняет проблему (код в проводнике компилятора):
template<typename T>
struct X
{
using Value = int;
};
template<typename FOO>
struct Foo
{
template<typename X<FOO>::Value VALUE>
struct Bar;
};
template<typename FOO>
template<typename X<FOO>::Value VALUE>
struct Foo<FOO>::Bar { static void test(); };
template<typename FOO>
template<typename X<FOO>::Value VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}
int main() { return 0; }
Вы также можете исправить это, просто используя жестко закодированный Value
тип (код в проводнике компилятора) — но это, вероятно, не то, что вам нужно:
template<typename FOO>
struct Foo
{
template<int VALUE>
struct Bar;
};
template<typename FOO>
template<int VALUE>
struct Foo<FOO>::Bar { static void test(); };
template<typename FOO>
template<int VALUE>
void Foo<FOO>::Bar<VALUE>::test() {}
int main() { return 0; }
Надеюсь, это поможет!
Комментарии:
1. Спасибо, ваш первый пример был полезен для лучшего понимания проблемы.