mike
mike

Reputation: 1720

Correct syntax for friend template function

In The C++ Programming Language, Fourth Edition - chapter 23.4.7 Friends, I found following example (I have slightly modified it to show only relevant part):

template<typename T>
class Vector {
public:
    friend Vector operator*<>(const Vector& v, int f); 
                           ^^ ~~~~ ?
};

template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

I tried to compile it, but I get following error (clang):

main.cpp:8:20: error: friends can only be classes or functions
        friend Vector operator*<>(const Vector& v, int f); 
                      ^
main.cpp:8:29: error: expected ';' at end of declaration list
        friend Vector operator*<>(const Vector& v, int f); 
                               ^
                               ;
2 errors generated.

Book explains that :

The <> after the name of the friend function is needed to make clear that the friend is a template function. Without the <>, a non template function would be assumed.

And that is all on this.

Without <> this code compiles, but when operator* is used (ex.: Vector<int> v; v*12;) then linker error appears:

main.cpp:(.text+0xb): undefined reference to `operator*(Vector<int> const&, int)'

So I assume that <> is needed to tell compiler that function template for operator* should be generated each time Vector template is instantiated for given type.

But what am I doing wrong in the example from the book, and why?

Upvotes: 5

Views: 2684

Answers (5)

Ave Milia
Ave Milia

Reputation: 649

Using <> is what C++ FAQ suggests, too.

But you can solve it by simply using the templated declaration like you would normally, except the parameters must be named differently from the class parameters. Then in the separate definition you can again use any type names:

template <typename T>
class Vector {
 public:
  T i{};
  // Typename must be different from the class typename(s).
  template <typename T_1>
  friend ostream& operator<<(ostream& os, const Vector<T_1>& v);
};

// Typename can be any.
template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& v) {
  return os << v.i;
}

Live demo

That's all. No need for weird <> in-between function declaration, or pre-declarations.

Upvotes: 0

dodo951
dodo951

Reputation: 454

To make template friend method syntax work you need a forward declaration of this template method.

template<typename T>
class Vector;

template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);

template<typename T>
class Vector
{
    template<typename T_> friend
    Vector<T_> operator*(const Vector<T_>& v, int f);
};

template<typename T>
Vector<T> operator*(const Vector<T>& v, int f)
{
    return v;
}

Upvotes: 2

Peter
Peter

Reputation: 36597

Whatever book you're using is explaining it incorrectly.

What you need to do is

template<typename T>
class Vector
{
       public:
           friend Vector<T> operator*(const Vector<T>& v, int f); 
};

template<typename T>
   Vector<T> operator*(const Vector<T>& v, int f)
{
    return v;
}

The above makes the operator*() which accepts a Vector<T> a friend of Vector<T> but not a friend of Vector<U> (unless T is the same type as U).

Within the class definition it is possible to leave out the <T> from Vector<T>, but in my experience mere human beings seem to have more trouble convincing themselves that the function declaration and function definition correspond to each other. So I generally prefer not doing that .... your call though.

The <> syntax is used when explicitly specialising templates, but that's not what you are trying to do. For example, with a templated function;

 template <class T> void foo(T) { /* whatever */   }
 template<> void foo<int> {/* something specific to int */ }

Upvotes: 0

Vittorio Romeo
Vittorio Romeo

Reputation: 93264

In your case, you're declaring operator* as a friend directly inside Vector, without any previous declaration. Therefore the correct syntax is:

template<typename T>
class Vector {
public:
    template<typename>
    friend Vector operator*(const Vector& v, int f);               
};

template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

live example on wandbox

Upvotes: 4

songyuanyao
songyuanyao

Reputation: 172894

As the book said,

the <> after the name of the friend function is needed to make clear that the friend is a template function.

That means, the name should refer to a function template, which should be declared (as template) in advance. e.g.

// forward declaration of the class template
template<typename T>
class Vector;

// declaration of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f);

template<typename T>
class Vector {
public:
    // friend declaration
    friend Vector operator*<>(const Vector& v, int f); 
};

// definition of the function template
template<typename T>
Vector<T> operator*(const Vector<T>& v, int f) {
    return v;
}

Upvotes: 10

Related Questions