Друг специализация шаблона без <> - программирование
Подтвердить что ты не робот

Друг специализация шаблона без <>

С++ 03 и С++ 11 имеют в первом абзаце [temp.friend]:

[Отредактированная цитата. Первая попытка пропустила вторую разницу в формулировках.]

Для объявления функции друга, которое не является объявлением шаблона:

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

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

  • [С++ 03:], если имя друга является квалифицированным идентификатором, и соответствующая специализация шаблона функции находится в указанном классе или пространстве имен, объявление друга относится к этой специализации шаблона, в противном случае

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

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

[Изменение в формулировке выглядит как пояснение для меня. Хотя я предполагаю, что могут быть разные способы интерпретации формулировки С++ 03 о "нахождении специализации в классе или пространстве имен".]

Мне интересна эта третья пуля. Я написал этот код, чтобы попытаться соответствовать его требованиям, но оба g++ 4.8.1 и clang++ 3.4 отклоняют код, будь то с -std = С++ 03 или -std = С++ 11:

template <class T> class R;
namespace N {
    template <class T> void test(const R<T>&);
}

template <class T>
class R {
    friend void N::test(const R<T>&);  // 8
    int m;
};

template <class T>
void N::test(const R<T>& rec) { rec.m; }

int main() {
    R<int> r;
    N::test(r);
}

Конечно, если я изменю строку 8 на

friend void N::test<>(const R<T>&);

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

Но не должен ли описанный выше код третьей крышкой и действителен? Объявление друга не является объявлением шаблона и использует идентификатор, который не является идентификатором шаблона в качестве имени. И нет никакой декларации функции nontemplate для второго пуля.

Это просто ошибка компилятора, общая для обоих? Или я что-то неправильно понял, и если да, то есть ли пример программы, демонстрирующей эту третью пулю?

4b9b3361

Ответ 1

в строке // 8, модифицированный код: friend void N::test< R<T> >( R<T>&); тоже.

friend void N::test<R<T>>(const R<T>&);//one type is friend with one type  #1
friend void N::test<>(const R<T>&);// one type is friend with one type    #2

Я использую некоторое доказательство кода, что # 1 равно # 2

Наконец, я пытаюсь ответить на ваш вопрос. Я не уверен, что это правильно.

 friend void N::test(const R<T>&);

При создании экземпляра класса R R<T> является известным типом. Однако функция

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

Функция friend - это функция, которая не существует. С точки зрения грамматики,

компилятор подскажет вам, что это функция, а не шаблон

N::test (r);

В этом месте функция создается, но компилятор не соответствует

друга перед объявлением в классе R, потому что вы не объявляете в качестве шаблона в R

вы просто объявляете функцию.

Ответ 2

Я думаю, что &lt > - условие вывода, так как из 14.8.2.6,

В объявлении, декларатор-id которого ссылается на специализацию шаблона функции, выполняется вывод аргумента шаблона для определения специализации, к которой относится объявление. В частности, это делается для явных инстанций (14.7.2), явных специализаций (14.7.3) и некоторых объявлений друзей (14.5.4).

В этом случае идентификатор декларатора не является специализацией, поэтому дедукция не выполняется.

Ответ 3

N:: test - это шаблонная функция, которая принимает класс под названием T. Это класс не называется R<T>. Измените функции соответствующим образом, и они будут работать.

namespace N
{
    template <class T>
    void test ( const T & );
}

template <class T>
class R
{
    friend void N::test ( const R<T> & );
    int m;
};

template <class T>
void N::test ( const T & rec ) { rec.m; }

int main ( )
{
    R<int> r;
    N::test ( r );
}