Question

This is a pretty short snippet that just won’t compile with g++ 4.7.1 (it won’t compile either with gcc 4.6.3 by the way).

#include <iostream>

template<typename T>
struct Foo
{
    template<typename U>
    friend std::ostream& operator<<(Foo&, U&);
};

template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u)
{
    std::cout << u;
    return std::cout;
}

int main()
{
    Foo<int> f;
    f << "bar";
    return 0;
}

And this is what gcc 4.7.1 outputs (4.6.3 says almost the same thing).

/tmp/ccNWJW6X.o: In function main': main.cpp:(.text+0x15): undefined reference tostd::basic_ostream >& operator<< (Foo&, char const (&) [4])' collect2: ld returned 1 exit status

Anyone could explain why?

EDIT

I also tried with clang 3.1, and it says exactly the same thing.

Was it helpful?

Solution

Friendship with templates can be a bit complicated... Lets see what your code does:

template<typename T>
struct Foo {
    template<typename U>
    friend std::ostream& operator<<(Foo&, U&);  // [1]
};
template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u) {    // [2]
    std::cout << u;
    return std::cout;
}

When you instantiate Foo with a type, for example int the friend declaration in [1] declares a template function:

template <typename U>
std::ostream& operator<<(Foo<int>&,U&);

But that function does not exist anywhere, what you are providing in [2] is a template that takes two arguments:

template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u);

The key point is that the friend declaration is processed while the template is being instantiated, and at that time Foo represents the type obtained with the current instantiation.

There are different options for what you want to do, the simplest is changing the friend declaration to:

template<typename W, typename U>
friend std::ostream& operator<<(Foo<W> foo, U& u);

Which declares a template taking two arguments (both W and U are unbound here), and matches your definition at namespace level.

Another option is defining the friend function inside the class template definition, in which case you can maintain the original signature. For more information on the different alternatives, take a look at this other answer

OTHER TIPS

You did not actually write the output operator<< for Foo

Notice the signatures for the two functions are very different

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top