Как правильно определить функцию друга вне класса шаблона? - PullRequest
0 голосов
/ 11 октября 2018

Если у меня есть нормальный класс, я могу «внедрить» в него несвободную функцию друга.(Это среди прочего может быть найдено только ADL).

case 1:

class A{
  double p_;
  friend double f(A const& a){return a.p_;}
};

Если вместо этого это класс шаблона, я могу сделать:

case 2:

template<class T>
class A{
  double p_;
  friend double f(A const& a){return a.p_;} // apparently A const& is a synomyn for A<T> const&
};

Теперь предположим, что мне нужно реализовать f в терминах класса, который необходимо определить позже.В таком случае я пытался сделать это:

дело 3:

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

Это уже дает предупреждение:'объявляет не шаблонную функцию [-Wnon-template-friend] ".

Следуя советам компилятора, я могу сделать это:

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 const& a);
};

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

Для чего требуется гораздо больше кода иЯ даже не уверен, что это на 100% эквивалентно случаю 2 abov, и это именно то, что я хочу, потому что теперь у меня есть действительно бесплатная функция, которая оказывается другом вместо введенного друга.

МожетСлучай 3 следует изменить, чтобы он был на 100% эквивалентен случаю 2 и по-прежнему иметь определение f вне класса?Другими словами, можно ли внедрить функцию друга, определенную вне класса?


Я тоже это попробовал, что выдает ошибку компилятора:

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

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

Thisanswer находит то же решение, но не отвечает на вопрос о том, эквивалентен ли случай 3 случаю 2. Как правильно написать объявления функций-друзей в классе шаблона?

1 Ответ

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

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

Более того, в случае 2 функция не шаблон.даже если у вас есть один для каждого шаблона.Таким образом, чтобы реализовать его вне класса, вам нужно будет реализовать каждый friend double f(A<T> const& a); для каждого T.

. Совет - самый близкий обходной путь:

  • Ваша функция (только специализация) является другом.
  • но ваша функция является шаблоном (поэтому должно произойти удержание:
    с friend double f(A<T> const& a, T); (случай 2), f(A<float>{}, 42); будет успешным
    , тогда как friend double f<>(A<T> const& a, T); не будет
    (T будет float для A<float> и int для 42))

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

Теперь предположим, что мне нужно реализовать f в терминах класса, который необходимо определить позже.В таком случае я пытался сделать это:

Другой способ - объявить закрытый метод, который будет выполнять эту работу, который позволит вам иметь определение друга внутри класса.Этот закрытый метод может быть определен позже:

template<class T>
class A{
    double p_;

    double do_f() const;
    friend double f(A const& a){return a.do_f();}
};

// Thing needed by A<T>::do_f

template<class T>
double A<T>::do_f() const
{
    // ...
}

Если тип возвращаемого значения является неполным типом, вы должны выполнить трюк с возвращением auto (это работает в g ​​++ 11 и clang++ 11).

template<class T> class A;
class B;

template<class T>
class A{
    B do_f() const;
    friend auto f(A const& a){return a.do_f();} // not friend B f(...
};

class B{};

template<class T> B A<T>::do_f() const{return B{};}

int main(){A<double> a; f(a);}
...