Сбой объявления специалиста шаблона - PullRequest
8 голосов
/ 15 декабря 2011

Следующий код, содержащий объявление друга, завершается с указанной ошибкой (см. http://ideone.com/Kq5dy):

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void foo<T>(); // error: variable or field 'foo' declared void
};

int main()
{
   foo<int>();
}

Если порядок объявления друзей и функций-членов поменялся местами, то код компилируется без проблем (см. http://ideone.com/y3hiK):

template<class T> void foo() {}

template<typename T>
class A {
   friend void foo<T>();
   void foo();
};

int main()
{
   foo<int>();
}

Этого не происходит, если объявление друга не содержит шаблонной специализации: подойдут не друзья по шаблону, а друзья по шаблону. Также использование квалифицированного имени в специализации шаблона позволяет компилировать код. Мой вопрос: почему первый пример терпит неудачу? Кажется, компилятор ищет имена в области видимости класса в момент объявления друга и только для специализации шаблона? Где в стандарте указано это поведение?

1 Ответ

7 голосов
/ 15 декабря 2011

Чтобы четко указать, что именно эту функцию вы хотите - friend, добавьте к имени функции ::, чтобы сказать, что она находится в глобальном пространстве имен.

Фрагмент, который компилируется и выполняет то, что вы хотите:

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void ::foo<T>();
};

int main()
{
   foo<int>();
}

n1905.pdf

3,4 / 9 Поиск имени

Поиск именидля имени, используемого в определении функции-друга (11.4), определенной inline в классе, предоставляющем дружбу, должно действовать, как описано для поиска в определениях функций-членов.Если функция друга не определена в классе, предоставляющем дружбу, поиск имени в определении функции друга должен продолжаться, как описано для поиска в определениях функций-членов пространства имен

Ваш фрагмент не компилируется по той же причинепоскольку приведенный ниже код не скомпилируется.

template<class T> void foo () {}

template<typename T>
struct A { 

  void foo (); 

  void func () {
    foo<T> (); // when performing the name lookup A::foo is
               // found before ::foo<T>
  }
};

...

14.5.3 Friends [temp.friend] 1

Другом класса или шаблона класса может быть шаблон функции или шаблон класса, специализация шаблона функции или шаблона класса или обычная (не шаблонная) функция или класс.Для объявления функции друга, которое не является объявлением шаблона:

- если имя друга является квалифицированным или неквалифицированным идентификатором шаблона, объявление друга ссылается на специализацию шаблона функции, в противном случае

- если имя друга является определенным идентификатором и соответствующая не шаблонная функция найдена в указанном классе или пространстве имен, объявление друга ссылается на эту функцию, в противном случае,

- еслиимя друга - это квалифицированный идентификатор, и соответствующая специализация шаблона функции находится в указанном классе или пространстве имен, объявление друга ссылается на эту специализацию шаблона функции, в противном случае,

- имя должно бытьнезавершенный идентификатор, который объявляет (или повторно объявляет) обычную (не шаблонную) функцию.

...