Все ниже сказанное, если вам не нужен оператор, чтобы быть другом, то не делайте его другом. Для операторов вывода, в частности, на мой взгляд, вы не должны делать их друзьями. Это потому, что если ваш класс может быть выведен в поток, он должен иметь эквивалентные функции get
, которые предоставляют те же данные программно. И в этом случае вы можете написать operator<<
как не друга в терминах этих get
функций.
Если у вас есть веские основания для того, чтобы сделать их друзьями, вы можете определить друга
template <class A> class MyClass {
public:
friend ostream & operator<<(ostream & os, MyClass<A> const& mc) {
// ...
}
};
Таким образом, вам не нужно выражение template<...>
, которое возвращает тип A
. Общеизвестно, если вы определите оператор внутри шаблона. Обратите внимание, что даже если вы определили его внутри шаблона, это не функция-член. Он все еще не является членом, но имеет доступ к именам, объявленным в классе (например, параметр шаблона). Для каждого экземпляра MyClass
, который вы создаете, из этой функции-друга, которая печатает вещи, создается другая не шаблонная операторная функция.
Если вы хотите определить шаблон снаружи, вы должны предварительно объявить его, чтобы иметь возможность объявить данную специализацию как друга.
// predeclare it so you can make it a friend.
template <class A> class MyClass;
template <class A> ostream &operator<<(ostream &os, MyClass<A> const&);
template <class A> class MyClass{
public:
/* the "<A>" is needed - it says that a given instantiation of
that template is a friend, and not a non-template function. */
friend ostream & operator<< <A>(ostream & os, MyClass<A> const& mc);
};
template <class A>
ostream & operator<<(ostream & os, MyClass<A> const& mc){
// some code
return os;
}
Это делает operator<< <Foo>
другом MyClass<Foo>
. Если бы вы пропустили <A>
или также возможный пустой <>
, компилятор понял бы, что из сказанного вы сделали оператор не-шаблон , имеющий конкретные вместо шаблонных параметров в качестве друга.
Более простое, но менее "правильное" решение - заставить MyClass <Foo>
иметь в качестве друга все operator <<
экземпляров. Таким образом, теоретически operator << <Bar>
может получить доступ к закрытым членам MyClass <Foo>
. Это не то, что нужно, но это тоже работает, получая больше доступа, чем нужно. Это избавляет от необходимости объявления форварда:
template <class A> class MyClass{
public:
/* make all instantiations friends. */
template<typename T>
friend ostream & operator<<(ostream & os, MyClass<T> const& mc);
};
template <class T>
ostream & operator<<(ostream & os, MyClass<T> const& mc){
// some code
return os;
}