Что означает угловая скобка в объявлении функции как друга? - PullRequest
0 голосов
/ 11 октября 2018

Мне трудно понять нотацию <> в объявлении функции как друга.(Это происходит из-за необходимости определить тело функции, которая была введена другом во внешнюю свободную функцию.)

template<class T> class A;

template<class T> double f(A<T> const& a);

template<class T>
class A{
    double p_;
    friend double f<>(A<T> const& a); // same as friend double f<>(A const& a);
};

Это точно эквивалентно friend double f<T>(A<T> const& a);?Если да, то какова цель этой записи <>?В конце концов, f не имеет параметров шаблона по умолчанию.

В общем случае:

template<class T1, class T2, ...>
class A{
    double p_;
    friend double f<>(A const& a); // same as double f<T1, T2, ...>?
};

?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

В большинстве случаев, когда используется имя шаблона, компилятору необходимо определить аргументы шаблона, которые определяют точную специализацию шаблона, который он представляет.

Звучит так, как будто вы знакомыс тем, как это делается для шаблонов классов (игнорируя пакеты параметров шаблона для простоты):

  1. Каждый аргумент в <> является одним из аргументов шаблона, в порядке с начала.

  2. Если шаблон имеет больше параметров шаблона, чем аргументов в <>, аргументы шаблона по умолчанию используются для оставшихся позиций (и эти аргументы шаблона по умолчанию должны существовать).

Но для шаблонов функций существует третья возможность автоматического вывода аргументов шаблона.Возможно, вам знакома идея вывода аргументов шаблона из вызова шаблона функции в форме, подобной func(a1, a2).Но вычет также возможен в форме, подобной func<x1, x2>(a1, a2), и может смешиваться и сопоставляться с другими источниками аргументов шаблона (опять же игнорируя пакеты параметров шаблона):

  1. Каждый аргумент в <> - один из аргументов шаблона, в порядке с начала.Они заменяют соответствующие параметры шаблона повсюду в типе функции перед переходом к следующему шагу.

  2. Любые оставшиеся параметры шаблона могут быть выведены (из типов выражений аргументов в вызовеили из объявленных типов параметров при сопоставлении объявлений в случаях, подобных этому friend использование).

  3. Для любых оставшихся параметров шаблона, не указанных явно и не выведенных, аргумент шаблона по умолчанию может бытьиспользуемый.(Только C ++ 11 и более поздние версии - C ++ 03 вообще не позволял шаблонам функций иметь аргументы шаблона по умолчанию.)

Так что в случае вызова функции это допустимоиспользовать func<>(a1, a2), что означает, что все аргументы шаблона должны быть либо выведены из типов a1 и a2, либо взяты из аргумента шаблона по умолчанию.В основном это то же самое, что и func(a1, a2), за исключением того, что для func(a1, a2) разрешение перегрузки может выбрать функцию без шаблона, которая также называется func;но при использовании func<>(a1, a2) только шаблоны могут быть рассмотрены.

Аналогично, список аргументов шаблона может быть необходим в объявлении друга, чтобы компилятор знал, что он называет специализацию шаблона функции, а непростая не шаблонная функция.Снова, часто пустой список <> будет делать, предполагая, что все аргументы шаблона могут быть выведены из типов параметров функции.Обратите внимание на различия здесь:

template <class T> class A;

template <class X> void f1(A<X>);
template <class X> void f2(A<X>);
template <class X> void f3(A<X>);
template <class X> void f4(A<X>);

template <class T>
class A {
    // For each class type A<T>, declares just the one specialization f1<T>
    // to be a friend.  So f1<int>(A<int>) is a friend of A<int>, but is not
    // a friend of A<double>.
    friend void f1<T>(A<T>);

    // Exactly the same (but for f2<T>).
    // A is the "injected class name" typedef for A<T>.
    // The argument for f2's X is deduced to be X=T.
    friend void f2<>(A);

    // Declares ALL specializations of f3 to be friends of all specializations of A.
    template <class U>
    friend void f3(A<U>);

    // Declares a non-template function.  Each class type A<T> declares
    // a different function unrelated to the template f4 above or to
    // the f4 declared by other A<U> types.  You could define the
    // individual overloaded functions void f4(A<int>), void f4(A<double>),
    // etc., but only one at a time, and only if you know all the
    // possible types to be used!
    friend void f4(A);
};

В общем случае:

template<class T1, class T2, ...>
class A{
    double p_;
    friend double f<>(A const& a); // same as double f<T1, T2, ...>?
};

?

Возможно.Хотя дело не только в том, чтобы брать аргументы шаблона непосредственно из специализации включающего шаблона класса.Вывод аргумента шаблона может стать более изощренным.Например, если у нас есть

template <class T1, class T2> class A;

template <class X>
double f(A<X, X> const& a);   // #1
template <class X>
double f(A<X, X*> const& a);  // #2
template <class X, class Y>
double f(A<X, Y> const& a);   // #3

template <class T1, class T2>
class A {
    friend double f<>(A const&);
};

, то какие совпадения объявлений шаблонов будут фактически отличаться для разных специализаций A!Функция double f<int>(A<int, int> const&) из шаблона # 1 является другом A<int, int>, функция double f<int>(A<int, int*> const&) из шаблона # 2 является другом A<int, int*>, а функция double f<int*, int>(A<int*, int> const&) из шаблона # 3 является другом A<int*, int>.Никакие другие шаблонные специализации не являются друзьями этих трех специализаций A.

0 голосов
/ 11 октября 2018

Это то же самое, что и friend double f<T>(A<T> const&).Обычно вы используете пустые аргументы шаблона для устранения неоднозначности между функцией, не являющейся шаблоном f, и шаблоном функции f.Если бы у вас не было <>, компилятор создал бы совершенно отдельную не шаблонную функцию f, а другая f<T> не смогла бы получить доступ к закрытым членам.

template<class T> class A;
template<class T> double f(A<T> const& a);
template<class T>
class A {
  double p_;
  friend double f(A<T> const& a); // notice omission of <>, declared as non-template
};

template<class T>
double f(A<T> const& a) {
  return a.p_;
}

int main() {
  f<>( A<int>{} ); // 'double A<int>::p_' is private within this context
}

Является ли [sic] тем, что в более общем смысле:

template<class T1, class T2, ...>
class A{
    double p_;
    friend double f<>(A const& a); // same as double f<T1, T2, ...>?
};

Если, например, f объявлено вне класса как template<class...Ts>f(A<Ts...>);, тогда да, они эквивалентны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...