简体   繁体   中英

Explicit specialization of friend function for a class template

I was reading litb's answer to a question here , where he details how to create a specialized friend function of a class template .

I tried to create an exemplar which did just what he suggests ( code at the end ):

// use '<>' to specialize the function template with the class template's type
friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f)

It results in a compiler error :

error: defining explicit specialization ‘operator<< <>’ in friend declaration

Explicitly declaring the template parameter in the specialization doesn't work either:

friend std::ostream& operator<< <T>(std::ostream& os, const foo<T>& f) // same error

On the other hand, changing from using a specialization to use a friend function template instead does work:

template<typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works

So my questions are:

  • what is causing the first error?
  • how can I explicitly specialize the ostream operator for the surrounding class template specialization?

Exemplar code below:

#include <iostream>

// fwd declarations
template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);

template<typename T>
struct foo
{
    foo(T val)
        : _val(val)
    {}

    friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f) // error line
    //template<typename U>
    //friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
    {
        return os << "val=" << f._val;
    }

    T _val;
};


int main()
{
    foo<std::string> f("hello world");
    std::cout << f << std::endl;
    exit(0);
}

In litb's example, he's just declaring the specialization as a friend in the class. He's not defining the specialization, which is what your code's doing. You're not allowed to define a specialization in a class declaration (or any non-namespace scope).

What you need is something like:

template <class T>
class foo;

template<class T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
    return os << "val=" << f._val;
}

template<typename T> 
struct foo
{
    // ...
private:
    friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);
    T _val;
};

You have 2 choices:

Remove fwd declarations and define everything in class.

Example

template <typename U>
friend std::ostream& operator<<(std::ostream& os, const foo<U>& f) // this works
{
    return os << "val=" << f._val;
}

Define friend function outside of the class.

Example

template<typename T> struct foo;
template<typename T> std::ostream& operator<<(std::ostream&, const foo<T>&);

template<typename T>
struct foo
{
    foo(T val)
        : _val(val)
    {}

    friend std::ostream& operator<< <>(std::ostream& os, const foo<T>& f);

    T _val;
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const foo<T>& f)
{
       return os << "val=" << f._val;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM