Overloading Output operator for a class template in a namespace
c++, friend, operator-overloading, outputstream, templates
Solution
You need to move your implementation of `operator<<` into the same namespace as your class. It's looking for:
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
But won't find it because of a short-coming in argument-dependent look-up (ADL). ADL means that when you call a free function, it'll look for that function in the namespaces of it's arguments. This is the same reason we can do:
std::cout << "Hello" << std::endl;
Even though `operator<<(std::ostream&, const char*)` is in the `std` namespace. For your call, those namespaces are `std` and `skg`.
It's going to look in both, not find one in `skg` (since yours is in the global scope), then look in `std`. It will see possibilities (all the normal `operator<<`'s), but none of those match. Because the code running (the code in `ostream_iterator`) is in the namespace `std`, access to the global namespace is completely gone.
By placing your operator in the same namespace, ADL works. This is discussed in an article by Herb Sutter: "A Modest Proposal: Fixing ADL.". (PDF). In fact, here's a snippet from the article (demonstrating a shortcoming):
// Example 2.4
//
// In some library header:
//
namespace N { class C {}; }
int operator+( int i, N::C ) { return i+1; }
// A mainline to exercise it:
//
#include <numeric>
int main() {
N::C a[10];
std::accumulate( a, a+10, 0 ); // legal? not specified by the standard
}
Same situation you have.
The book "C++ Coding Standards" by Sutter and & Alexandrescu has a useful guideline:
- Keep a type and its nonmember function interface in the same namespace.
Follow it and you and ADL will be happy. I recommend this book, and even if you can't get one at least read the PDF I linked above; it contains the relevant information you should need.
Note that after you move the operator, you'll need your friend directive (so you can access private variables):
template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);
And ta-da! Fixed.
Problem
I've this program ``` #include <iostream> #include <sstream> #include <iterator> #include <vector> #include <algorithm> using namespace std ; #if 0 namespace skg { template <class T> struct Triplet ; } template <class T> ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t) ; #endif namespace skg { template <class T> struct Triplet { // friend ostream& ::operator<< <> (ostream& os, const Triplet<T>& p_t) ; private: T x, y, z ; public: Triplet (const T& p_x, const T& p_y, const T& p_z) : x(p_x), y(p_y), z(p_z) { } } ; } template <class T> ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t) { os << '(' << p_t.x << ',' << p_t.y << ',' << p_t.z << ')' ; return os ; } namespace { void printVector() { typedef skg::Triplet<int> IntTriplet ; vector< IntTriplet > vti ; vti.push_back (IntTriplet (1, 2, 3)) ; vti.push_back (IntTriplet (5, 5, 66)) ; copy (vti.begin(), vti.end(), ostream_iterator<IntTriplet> (cout, "\n")) ; } } int main (void) { printVector() ; } ``` Compilation fails because compiler could not find any output operator for skg::Triplet. But output operator does exist. If I move Triplet from skg namespace to global namespace everything works fine. what is wrong here ?