g ++ и clang ++ различное поведение с функцией-другом, определенной внутри класса-шаблона - PullRequest
0 голосов
/ 06 мая 2018

Еще один вопрос типа "кто прав между g ++ и clang ++?" для C ++ стандартных гуру.

следующий код

template <int>
struct foo
 {
   template <typename>
   friend void bar ()
    { }
 };

int main ()
 {    
   foo<0>  f0;
   foo<1>  f1;
 }

компилируется без проблем с clang ++ (только два предупреждения «неиспользуемая переменная»), но выдает следующую ошибку

tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12:   required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
    friend void bar ()
                ^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here

компиляция с g ++.

Вопрос, как обычно, таков: кто прав? g ++ или clang ++?

Проверено clang ++ 3.9.1 и g ++ 6.3.0 на моей платформе Debian. Но, пробуя в Wandbox, кажется, равняется более поздним версиям.

1 Ответ

0 голосов
/ 06 мая 2018

GCC прав в этом случае.

Соответствующая стандартная формулировка: [temp.inst] / 2 :

Неявная реализация специализации шаблона класса вызывает
- неявное создание деклараций, но не определения, не удаленных функций-членов класса, член классы, перечисления членов в области, статические члены данных, член шаблоны и друзья; и
[...]
Тем не менее, с целью определение того, является ли конкретное объявление действительным в соответствии 6.2 и 12.2, декларация, которая соответствует определению в Шаблон считается определением. [ Пример: [...]

template<typename T> struct Friendly {
   template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)

- конечный пример ]

Детали, относящиеся к друзьям, были добавлены в этот параграф DR2174 и опубликованы на C ++ 17 (это отчет о дефектах, поэтому компиляторы должны применять его и к предыдущим стандартным версиям).


Последние версии MSVC и EDG в строгом режиме также отклоняют код, жалуясь на переопределение.

[temp.inject] / 1 в некоторой степени связан, но в нем говорится только о функциях друзей, а не о шаблонах функций друзей:

Дружественные классы или функции могут быть объявлены в шаблоне класса. Когда создается экземпляр шаблона, обрабатываются имена его друзей как будто специализация была явно объявлена ​​в ее точке конкретизации.

...