Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit specialization of friend function for a class template

Tags:

c++

templates

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);
}
like image 485
Steve Lorimer Avatar asked Nov 19 '12 23:11

Steve Lorimer


People also ask

Can we declare a template function as the friend of the class?

A template friend declaration can name a member of a class template A, which can be either a member function or a member type (the type must use elaborated-type-specifier).

Is specialization of template C++?

It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.

What is function template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is friend function and friend class explain with example?

A friend function is a special function in C++ which in-spite of not being member function of a class has privilege to access private and protected data of a class. A friend function is a non member function or ordinary function of a class, which is declared as a friend using the keyword “friend” inside the class.


2 Answers

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;
};
like image 56
je4d Avatar answered Oct 06 '22 22:10

je4d


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;
}
like image 32
Jesse Good Avatar answered Oct 06 '22 22:10

Jesse Good