Если вы действительно хотите определить оператор извне и подружиться только с экземпляром оператора, который совпадает по типу с этим экземпляром шаблона, правильный синтаксис:
template <typename T> class test; // forward declare template class
template <typename T> // forward declare the templated operator
std::ostream& operator<<( std::ostream&, test<T> const & );
template <typename T>
class test { // define the template
friend std::ostream& operator<< <T>( std::ostream&, test<T> const & ); // befriend
};
template <typename T> // define the operator
std::ostream& operator<<( std::ostream& o, test<T> const & ) {
return o;
}
В большинстве случаев это не стоит хлопотвытащить определение из класса, учитывая, что вам все еще нужно предоставить его в заголовке и требовать дополнительной работы.
Также обратите внимание, что у компилятора есть небольшие различия в отношении поиска.В случае, когда функция встроена в определение класса, компилятор не найдет эту функцию , если только один из аргументов на самом деле не относится к типу шаблона, поэтому он эффективно уменьшает видимость и количестворабота, которую должен выполнить компилятор (если шаблонное operator<<
определено вне класса, компилятор найдет его в качестве кандидата для разрешения перегрузки во всех местах, где он находит a << b
, только чтобы отбросить его во всех случаях, когдавторой аргумент не является test<T>
(и он будет показывать шаблонный оператор в качестве кандидата во всех сообщениях об ошибках, где он не может соответствовать operator<<
, который уже является достаточно длинным списком).