Следующий фрагмент кода не может правильно собрать как с G ++ и Clang ++, независимо от стандартной С ++ требуется (98, 11, 14):друга определение функции состоит в шаблонах класса
$ cat foo.cc
template <typename T>
struct foo
{
friend void bar(){}
};
int main()
{
foo<int> fi;
foo<char> fc;
}
, например:
$ clang++-mp-3.7 -std=c++14 foo.cc
foo.cc:4:15: error: redefinition of 'bar'
friend void bar(){}
^
foo.cc:10:13: note: in instantiation of template class 'foo<char>' requested here
foo<char> fc;
^
foo.cc:4:15: note: previous definition is here
friend void bar(){}
^
1 error generated.
Я знаю, что могу обойти эту проблему, поставив определение (не объявление) bar
из foo
, я не прошу обходного. Скорее, я хотел бы понять, что происходит. Поэтому у меня есть два вопроса:
Во-первых, я не вижу, где в стандарте это поведение документировано или подразумевается. Я сомневаюсь, что и G ++, и Clang ++ получили бы это неправильно, поэтому я ожидал, что он где-то документирован/подразумевается.
Во-вторых, в чем смысл такого поведения? Существует ценность в определении друзей внутри класса (см., Например, Is there any difference if we define friend function inside or outside of class), так что же важно сохранить это поведение. Я имею в виду, не должен ли стандарт воспринимать поведение, как ожидал бы один (I)?
Интересно. Мое наивное предположение состояло бы в том, что должны быть два 'bar', один' foo :: bar' и один 'foo :: bar' (ну, не совсем, но близко) - каждый друг в лексической сфере класс, о котором идет речь. Только функции, не определенные в строке, должны находиться в области охватывающего пространства имен. Но я не понимаю эту часть стандарта достаточно хорошо, чтобы сделать хороший аргумент. –
Yakk
Необязательно иметь друга 'foo', который не зависит от 'T'. Для чего нужна дружба? –
Это потому, что я с удовольствием снял реальный случай. Но на самом деле вы помогли мне понять, что было действительно неправильно в реальной реализации: «bar» снова был затенен («T2») вместо того, чтобы быть тем, как я написал его здесь. Но тогда, поскольку его подлинная подпись действительно принимает аргумент 'foo', генерируемые подписи для сгенерированных друзей _are_ разные, и все работает так, как ожидалось. Благодаря! –
akim