Reputation: 1720
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
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;
}
That's all. No need for weird <>
in-between function declaration, or pre-declarations.
Upvotes: 0
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
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
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;
}
Upvotes: 4
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