The following example compiles fine but I can't figure out how to separate declaration and definition of operator<<() is this particular case.
Every time I try to split the definition friend is causing trouble and gcc complains the operator<<() definition must take exactly one argument.
#include <iostream>
template <typename T>
class Test {
public:
Test(const T& value) : value_(value) {}
template <typename STREAM>
friend STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
os << rhs.value_;
return os;
}
private:
开发者_开发技巧 T value_;
};
int main() {
std::cout << Test<int>(5) << std::endl;
}
Operator<<() is supposed to have a free first parameter to work with different kind of output streams (std::cout, std::wcout or boost::asio::ip::tcp::iostream). The second parameter should be bound to a specialized version of the surrounding class.
Test<int> x;
some_other_class y;
std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works
std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works
Besides that using a non-member-function isn't equivalent to splitting the definition and declaration because non-member-functions can't access private attributes the the class.
The easiest is probably to make all these template operators friends:
#include <iostream>
template <typename T>
class Test
{
public:
Test(const T& value) : value_(value) {}
template <typename STREAM, typename U>
friend STREAM& operator<<(STREAM& os, const Test<U>& rhs);
private:
T value_;
};
template <typename STREAM, typename T>
STREAM& operator<<( STREAM& os, const Test<T>& rhs )
{
os << rhs.value_;
return os;
}
The nearest I can achieve is
#include <iostream>
template <typename T>
class Test;
template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs);
template <typename T>
class Test {
public:
Test(const T& value) : value_(value) {}
template <typename STREAM, typename U>
friend STREAM& operator<< (STREAM& os, const Test<U>& rhs);
private:
T value_;
};
template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
os << rhs.value_;
return os;
}
int main() {
std::cout << Test<int>(5) << std::endl;
}
which declares all operator<< as friend instead of only the one parametrized by T. The problem is that it isn't possible to partially specialize functions. One would have liked to use
template <typename STREAM>
friend STREAM& operator<< <STREAM, T> (STREAM& os, const Test<T>& rhs);
but that isn't valid syntax. (Well, and partial specialization can't declared friend)
Shouldn't it be defined outside of the class ?
template <typename T>
class Test
{
...
template <typename STREAM>
friend STREAM& operator<<(STREAM& os, const Test<T>& rhs);
};
template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs)
{
os << rhs.value_;
return os;
}
The problem is that in the code that you present the friend is a templated function parametrized only on the first argument type. That is, for each instantiating type T of the class template (call it mytype
), you are declaring a free template function:
template <typename STREAM>
STREAM& operator<<( STREAM& os, Test<mytype> const & x );
The important point there is that Test<mytype>
is the particular instantiation of Test
with type argument mytype
.
If you really want to declare a friend function that is templated in both the stream type and the instantiating type of the Test
template, you must declare a friend with two arguments.
On the other hand, I recommend that you do not parametrize operator<<
on the stream type, and at the same time, that you define it inside the class braces as it has slight advantages (name lookup rules are slightly different).
For each instantiated type T of class Test a template function operator<<() is exposed which can operate on different kind of streams. The operator<<() function has a free first parameter but a fixed second parameter.
example:
Test<int> x;
some_other_class y;
std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works
std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works
That's the way the Test class was supposed to work.
精彩评论