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?
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;
}
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
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;
}
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 */ }
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.
Related
I am wondering how to make a function friend of a class and define the function outside class if the function's template arguments include but are not limited to the class's template arguments.
For example, I have the following template class and template friend function:
template<int N> class Matrix;
template<typename T, int N> Matrix<N> operator*(const Matrix<N> &m1, const T &m2);
// class definition
template<int N>
class Matrix{
template<typename T>
friend Matrix<N> operator* (const Matrix<N> &m1, const T &m2);
};
// friend function definition
template<typename T, int N> Matrix<N> operator*(const Matrix<N> &m1, const T &m2)
{
return m1; // just as an example
}
If I compile:
Matrix<3> m;
m * 1.0;
I would get the following linker error:
test.cc:(.text+0x1c7): undefined reference to `Matrix<3> operator*<double>(Matrix<3> const&, double const&)'
collect2: error: ld returned 1 exit status
You have a mismatch in kind.
Your initial declaration, and later definition, have this signature:
template<typename T, int N>
Matrix<N> operator*(const Matrix<N> &m1, const T &m2);
This is a function template taking two template parameters: T and N.
However, within your class, you make as a friend a function template that has this signature:
template<typename T>
friend Matrix<N> operator* (const Matrix<N> &m1, const T &m2);
This only has one template parameter: T. N is fixed here. This friend declaration also declares this function template. This is a better match, but not actually defined, hence the behavior you see.
You have two options I think.
Remove the namespace-scope declaration of operator* and just declare and define the friended operator* within the definition of Matrix.
Change the friend declaration to match the namespace-scope declaration:
template<typename T, int M>
friend Matrix<M> operator* (const Matrix<M> &m1, const T &m2);
(1) is the better option typically - doesn't involve adding more operator*s into global scope, which is good for compile times.
I'm trying to write my own vector template class, but I have some problems when writing friend function declarations.
At first I wrote like this:
template <typename T, typename Alloc = std::allocator<T>>
class vector {
public:
friend bool operator==(const vector<T, Alloc>&, const vector<T, Alloc>&);
};
But the compiler reports a warning that I declare a non-template function. So I changed the friend declaration to this:
template <typename T, typename Alloc = std::allocator<T>>
class vector {
public:
template <typename E, typename F>
friend bool operator==(const vector<E, F>&, const vector<E, F>&);
};
So far everything is fine, but I think there are still problems. If I write like that, I make all operator== functions which take two template arguments as its friend functions. For example, operator==(const vector<int>&, const vector<int>&) and operator==(const vector<double>&, const vector<double>&) would both be vector<int>'s friend function.
What is the right way to write friend functions in template class?
Friend non-template function
But the compiler reports a warning that I declare a non-template function.
Yes, you're declaring a non-template function inside the class definition. That means if you define it out of the class definition, you have to define it as non-template function, and for all the possible instantiations , like:
bool operator==(const vector<int>& v1, const vector<int>& v2)
{
...
}
bool operator==(const vector<char>& v1, const vector<char>& v2)
{
...
}
That is ugly, you can define it inside the class definition like
template <typename T, typename Alloc = std::allocator<T>>
class vector {
public:
friend bool operator==(const vector<T, Alloc>&, const vector<T, Alloc>&) {
...
}
};
Friend function template
If you want to define it as template function, and constrain the scope of friendship, you can
// forward declaration
template <typename T, typename Alloc>
class vector;
// forward declaration
template <typename T, typename Alloc>
bool operator==(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2);
template <typename T, typename Alloc = std::allocator<T>>
class vector {
private:
int i;
public:
// only the instantiation of operator== with template parameter type of current T and Alloc becomes friend
friend bool operator==<>(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2);
};
template <typename T, typename Alloc = std::allocator<T>>
bool operator==(const vector<T, Alloc>& v1, const vector<T, Alloc>& v2)
{
...
}
Then, for vector<int>, only bool operator==(const vector<int>&, const vector<int>&) is friend, other instantiations like bool operator==(const vector<double>&, const vector<double>&) is not.
LIVE
Assume we have a template class with friend function:
template<class T>
class A {
friend A operator+ (int, const A&);
};
This function is implemented somewhere below:
template<class T>
A<T> operator+ (int i, const A<T>& a) {
...
}
And also there is force instantiation of class template further below:
template class A<int>;
Does this imply that operator+(int, A<int>) will be compiled? Or do I have to force instantiate it separately to achieve that?
Template parameters aren't automatically forwarded to friend declarations. You need to specify a template parameter for the function as well:
template<class T>
class A {
template<class U>
friend A<U> operator+ (int, const A<U>&);
};
Implementation is almost correct, should be
template<class T>
A<T> operator+ (int i, const A<T>& a) {
// ^^^
// ...
}
I prefer to write definitions for class and function templates in a separate file which is automatically included after the "public" header. However, I've come to an interesting case where it looks like I can't do that.
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
int main()
{
Type a;
Type b;
a == b;
}
Is it possible to write definition of operator== separately that will work for any T and U?
For a particular specialization, yes:
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
int x = 42;
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
bool operator ==(const Type& lhs, const Type& rhs) {
return lhs.x == rhs.x;
}
int main()
{
Type a;
Type b;
a == b;
}
In your example, each specialization of the template befriends a non-template function that takes that particular specialization as parameters. You could define this function in-class (and then it will be stamped out every time the template is instantiated), or you could define it out-of-class - but then you would have to define one for every specialization you ever use.
As Igor Tandetnik points out, your example declares a non-template friend function, which you'll have to overload for each template instantiation, which is one reason friend functions are allowed to be defined inline (so they can be generated by the template without having to be templates themselves).
If you want to define the friend function as a template, here is the closest I was able to come up with:
template <typename T>
struct Outer {
template <typename U>
struct Inner;
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );
template <typename T>
template <typename U>
struct Outer<T>::Inner {
friend bool operator==<T,U>(Inner const &, Inner const &);
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
return true;
}
// I switched this out, because my gcc-4.6 doesn't
// understand "using" aliases like this yet:
typedef Outer<int>::Inner<short> Type;
int main() {
Type a;
Type b;
operator==<int,short>( a, b );
}
Unfortunately, you'll notice the call site of this operator function is very awkward: operator==<int,short>( a, b ). I believe defining a function template on a nested class template like this disables (or at least interferes with) argument deduction, so you have to specify the template parameters explicitly (which means calling it as a function rather than in operator form). This is why the inline friend definition is so convenient. If you really want to define your operator=='s code separately, I'd recommend defining the friend inline to call another function template (with the proper template arguments), which you can then define out-of-line as a free function.
I'm having compile time trouble with the following code:
template <typename T,
template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b);
template <typename T, std::vector> // HERE
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
...
vector<int> a, b;
cout << is_in(a,b) << endl;
The error message is (on the line marked "HERE"):
error: 'std::vector' is not a type
(of course, I have included vector from std!). Any suggestion? I fiddled with it for a while, but I'm getting to the point where I could use some help :-) I need to partially specialize the initial template declaration so that I can have the compiler switch implementations depending on the actual type of the container C (there will be a is_in for sets, one for vectors, one for ranges..., with different algorithms each time).
Thanks!
The partial specialization of a function template is not allowed by the Standard.
A simple solution is : use overload.
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
This is overloaded function template. Its NOT partial specialization.
Or, you could do this:
namespace detail
{
template<typename T, typename C>
struct S
{
static bool impl(const C & a, const C & b)
{
//primary template
//...
}
}
template<typename T>
struct S<T, std::vector<T> >
{
static bool impl(const std::vector<T> & a, const std::vector<T> & b)
{
//partial specialization for std::vector
return false;
}
}
}
template <typename T, template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b)
{
return detail::S<T, C<T> >::impl(a,b);
}
Function template partial specialization is not allowed. In any case you're not using the template specialization syntax, you're actually writing an additional overload. Try this instead:
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
If partial specialization were allowed, it would look like this instead:
template <typename T> // std::vector is not a template parameter,
// so we wouldn't put it here
bool is_in<T, std::vector>(const std::vector<T>& a, const std::vector<T>& b)
// instead, it'd appear ^ here, when we're specializing the base template
{
return false; // implementation tbd
}
I don't know if it works (as template templates are always a trouble to my mind), but what about just trying
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
...
}
as it's a specialization.
EDIT: Others have clarified on this already, but I'll add it for completeness. The above code is actually an overload and not a partial specialization, but partial function specializations aren't allowed anyway.