The C++ FAQ offers guide how to write friend template declarations. I have a problem though when one of the arguments is a nested struct of the template class, e.g.:
template<typename T>
class MyClass;
template<typename T> QDataStream &operator<<(QDataStream &stream, const typename MyClass<T>::Node &node);
Neither of these versions work:
template<typename T>
class MyClass
{
private:
struct Node {};
friend QDataStream &operator<< <>(QDataStream &stream, const Node &node);
friend QDataStream &operator<< <>(QDataStream &stream, const MyClass::Node &node);
friend QDataStream &operator<< <>(QDataStream &stream, const MyClass::Node &node);
friend QDataStream &operator<< <>(QDataStream &stream, const typename MyClass<T>::Node &node);
friend QDataStream &operator<< <>(QDataStream &stream, const typename MyClass::Node &node);
};
template<typename T>
QDataStream &operator<<(QDataStream &stream, const typename MyClass<T>::Node &node)
{
return stream;
}
The error given (by MSVC 2017) is:
error: C2672: '<<': no matching overloaded function found
What would be the proper syntax to write this?
This operator<<
is never usable as an operator because T
only appears in a non-deduced context. For the same reason, the compiler can't deduce the template argument when trying to figure out exactly which specialization of which function template you are trying to match.
There's also the little problem that the specialization names the private member Node
to which it has no access (the compiler can't figure out that the friend
declaration is granting it such access until it figures out which specialization is being named by the declaration).
The usual fix is to either define the operator as an inline non-template function inside the class template definition, or extract Node
into its own class template.