Friend operators for template class - c++

I have a template class, to which I declared 2 operator+ methods. Their declaration is:
1) const MyClass<T> operator+ (int num) const;
and
2) friend const MyClass<T> operator+ <>(int num, const MyClass<T>& other);
Following this FAQ, the .hpp file looks something like this:
//forward declaration of the class.
template<class T>
class MyClass;
//forward declaration of the operator+
template<class T>
const MyClass<T> operator+ (int num, const MyClass<T>& other);
template<class T>
class MyClass {
public:
...
const MyClass<T> operator+ (int num) const;
friend const MyClass<T> operator+ <>(int num, const MyClass<T>& other);
...
};
(And later I have the definitions of those methods).
Note that the 2 operator+ methods are used in different situations:
The first in
MyClass mc;
mc+5;
And the second in
MyClass mc;
5+mc;
But for some reason, when I compile it in g++ (version 4.8.2, if that matters), I get the error:
declaration of ‘operator+’ as non-function
friend const MyClass<T> operator+ <>(int num, const MyClass<T>& other);
Note that the error refers to the friend operator+ method
But, if I remove the declaration of the first operator+ method (i.e. leaving only the friend one), then everything compiles just fine!
What is going on?

Not sure why, but switching the order makes it compile (will try to find an explaination):
//forward declaration of the class.
template<class T>
class MyClass;
//forward declaration of the operator+
template<class T>
const MyClass<T> operator+(int num, const MyClass<T>& other);
template<class T>
class MyClass {
public:
friend const MyClass<T> operator+<>(int num, const MyClass<T>& other);
const MyClass<T> operator+ (int num) const;
};
EDIT
Thanks to Maksim for pointing out that my doubts were true. What happens is that the names of both operators clash and thus the error. Normally the second operator would have the class name in it's name, but since in the class declaration you are inside class scope the names clash. If the non class member operator would be in a different namespace, e.g:
//forward declaration of the class.
template<class T>
class MyClass;
//forward declaration of the operator+
namespace Foo
{
template<class T>
const MyClass<T> operator+(int num, const MyClass<T>& other);
}
template<class T>
class MyClass {
public:
const MyClass<T> operator+ (int num) const;
friend const MyClass<T> Foo::operator+<>(int num, const MyClass<T>& other);
};
using namespace Foo;
int main()
{
MyClass<int> a;
5 + a;
}
it would be fine since the names would be distinct. Also if you would use them as friends on another object it would also be fine:
//forward declaration of the class.
template<class T>
class MyClass;
//forward declaration of the operator+
template<class T>
const MyClass<T> operator+(int num, const MyClass<T>& other);
template<class T>
class MyClass {
public:
const MyClass<T> operator+ (int num) const;
};
template <typename T>
class Foo
{
friend const MyClass<T> operator+<>(int num, const MyClass<T>& other);
friend const MyClass<T> MyClass<T>::operator+(int num);
};
int main()
{
MyClass<int> a;
5 + a;
}
I hope this explains these examples explain the cause.

For the most part, this is what you actually want:
template<class T>
class MyClass {
public:
MyClass operator+ (int num) const;
friend MyClass operator+(int num, const MyClass& other) {
return other+num;
}
};
I made a number of changes, all on purpose.
I removed the forward declaration of MyClass<T> and operator+, because neither are needed.
I made the non-member operator+ an inline friend, and no longer a template. This is what I call a Koenig operator: it can only be accessed via ADL (argument dependent lookup) on MyClass. It is not a template: however one independent non-template function is created for each template class.
As this function is almost certainly just going to mindlessly forward its arguments to the member operator+, I did it inline right there.
Finally, I removed const from the return type. const in return types does little except block some move optimizations.
The end result is code that is shorter, simpler and easier to work with.
I often go a step further when I want an industrial quality solution:
template<class T>
class MyClass {
public:
MyClass& operator+=(int num); // do actual work here
template<class Self>
friend MyClass operator+(int num, Self&& self) {
auto tmp = std::forward<Self>(self); // perfect forwarding
tmp += num; // delegate to +=
return tmp; // elide return value
}
template<class Self>
friend MyClass operator+(Self&& self, int num) {
return num + std::forward<Self>(self); // DRY principle
}
};
where I forward everything through to member +=. The above version also enables perfect forwarding of MyClass into +. While the operator looks overly greedy (I mean, it doesn't seem to restrict Self to be of type MyClass at all!), because it can only be found via ADL on MyClass<T>, self must be a reference to an instance of MyClass!
clang interestingly requires a template<class Self, std::enable_if_t<std::is_class<std::decay_t<Self>>{}>* = nullptr> for the operator+s due to it treating some restrictions on operator+ as hard errors, instead of SFINAE errors.
This strategy, basing other operators off += style operators, and using Koenig operators for + style operators that just forward to +=, works well in a wide variety of situations.
You can even use inheritance to strip out the boilerplate to convert += into +. This doesn't even require CRTP.
struct plus_impl {
template<class Self,
std::enable_if_t<std::is_class<std::decay_t<Self>>{}>* = nullptr
>
friend std::decay_t<Self> operator+(int num, Self&& self) {
auto tmp = std::forward<Self>(self); // perfect forward a copy
tmp += num; // delegate to +=
return tmp; // elide return value
}
template<class Self,
std::enable_if_t<std::is_class<std::decay_t<Self>>{}>* = nullptr
>
friend std::decay_t<Self> operator+(Self&& self, int num) {
return num + std::forward<Self>(self); // DRY principle
}
};
template<class T>
class MyClass : public plus_impl {
public:
MyClass& operator+=(int num){
std::cout << "+=" << num << "\n";
return *this;
}
};
live example.
We use the magic of ADL here. Inheriting from plus_impl means that MyClass<T> + int finds the operator+ in plus_impl. As operator+ is a template operator, it actually gets the MyClass<T> as a MyClass<T>, not as a plus_impl. The implementation of operator+ then uses MyClass<T>'s += to do the work.
I believe this technique is similar to how boost::operators work, except it uses CRTP (I remember some discussion about them using it because some older compilers didn't do the right thing without it?)
Another fun thing about this technique is that subclasses of MyClass<T> magically get + support.

I think this should look like this:
//forward declaration of the class.
template<class T>
class MyClass;
//forward declaration of the operator+
template<class T>
MyClass<T> operator+ (int num, const MyClass<T>& other);
template<class T>
class MyClass {
public:
MyClass<T> operator+ (int num) const;
template<typename P> friend MyClass<P> operator+ (int num, const MyClass<P>& other);
};
Returning const MyClass<T> make no sence because const is discarded anyway.

Related

Template class with implicit conversion and operator overload but not inline

Based on the answer in Implicit conversion when overloading operators for template classes I was able to write the following code that works perfectly fine (simplified example):
namespace my_library {
template <typename T>
struct Number {
T n;
inline Number(T n) : n(n) { }
friend Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
};
}
int main() {
return (int) (4 + my_library::Number<double>(3)).n; // returns 7
}
All I want to do is make it so that operator+ is not inlined within the definition of Number (but stays in the header file) while everything still works the same way - see the expression in the main function. Note that it requires that the integer 4 gets implicitly converted to double and then to Number<double>. I followed a comment linking to Binary operator overloading on a templated class but that solution did not work - the overloaded operator is no longer matched. Is there any way to make this work and have the body of the operator outside the struct definition? (Without complicating the operator interface or adding more overloads - in those cases I'd rather just keep it inlined.)
You can do it like this:
template <typename T>
struct Number {
// ...
template <class U>
friend Number<U> operator+(const Number<U> &a, const Number<U> &b);
};
template <typename U>
Number<U> operator+(const Number<U> &a, const Number<U> &b) {
return Number<U>(a.n + b.n);
}
In this example, operator+ will be a friend of all Number specializations even when the types don't match. This might be a broader friendship than you intended, but is the simplest way to achieve your objective of moving the definition of operator+ outside the definition of Number. Note that when a friend is not defined inline, you lose the benefit of having it as a "hidden friend". (A hidden friend can only be found via argument-dependent lookup, which means that the compiler will typically not have to consider it as a candidate function in most cases where it is not intended to be used.)
If you want each specialization of operator+ to only be a friend of one particular Number specialization where the types match, it is more complicated. You have to forward-declare the operator+ template in order to prevent the friend declaration from declaring a non-template function, and you also have to forward-declare Number so that it can be used in the operator+ forward declaration:
template <typename T> struct Number;
template <typename T>
Number<T> operator+(const Number<T>&, const Number<T>&);
template <typename T>
struct Number {
// ...
friend Number<T> operator+<>(const Number<T>&, const Number<T>&);
};
template <typename T>
Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}

friend operator in nested class of templated class

I want to add a iterator class type for my vector class,and I declare some compare operator as friend function of iterator class.but it didnt complie correctly,I did forward declaration.
template<class object>class vector;
template<class object>
bool operator<(typename vector<object>::const_iterator& lhs, typename vector<object>::const_iterator& rhs);
template<class object>class vector {
protected:
//some member
public:
class const_iterator {
friend bool operator< <>(const_iterator& lhs, const_iterator& rhs);
friend bool operator> <>(const_iterator& lhs, const_iterator& rhs);
//...
};
};
compiler said no matching overloaded function found,I use vs2019.I guess something wrong with forward declaration.
and another question is,I notice some people use this form when declare friend function inside class.
class myclass{
friend void foo<T>(T t);
//...
}
but when declare a operator as friend it's different
friend bool operator< <>(const myclass& lhs, const myclass& rhs);
I wonder what's the difference between these two.
please help me,thanks a lot.
In your forward declaration
template<class object>
bool operator<(typename vector<object>::const_iterator&,
typename vector<object>::const_iterator&);
const_iterator is in the non-deduced context, i.e. the compiler will not be able to deduce int for object in the following call:
vector<int>::const_iterator c1;
vector<int>::const_iterator c2;
c1 < c2;
I can suggest two solutions.
The simplest one: omit your forward declarations and provide a definition for operator< inside the body of const_iterator:
friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
... return ... ;
}
If you can't define operator< inside const_iterator, use CRTP to turn a non-deduced context into a deduced one:
template<class derived>
struct const_iterator_crtp {};
template<class derived>
bool operator<(const_iterator_crtp<derived>&,
const_iterator_crtp<derived>&);
template<class object>
struct vector {
struct const_iterator : const_iterator_crtp<const_iterator> {
using base = const_iterator_crtp<const_iterator>;
friend bool operator< <>(base&, base&);
private:
int priv;
};
};
template<class derived>
bool operator<(const_iterator_crtp<derived>& lhs,
const_iterator_crtp<derived>& rhs)
{
auto& l = static_cast<derived&>(lhs); // these static_cast's are safe
auto& r = static_cast<derived&>(rhs);
return l.priv < r.priv;
}
Is the operator< a function template in the first solution? Why we don't need a <> after operator<?
It is not a template. You don't need <> in this definition.
You forward declare a template first. Without <>, a friend declaration introduces a non-template function. A non-template function, even if it has the same name as template one (non-template and template functions can overload!), should be defined somewhere. You'll get a link error without such a definition. To override the default behavior and to refer to the function template that was forward declared earlier, you add <>.

Template parameter shadows with friend?

In the following example which overloads << operator:
#include <iostream>
template <typename T>
class MyClass {
public:
MyClass(T X, T Y):x(X), y(Y) {}
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
private:
T x;
T y;
};
template <typename T>
std::ostream& operator <<(std::ostream &os, const MyClass<T> &cl)
{
os << cl.x << " " << cl.y;
return os;
}
int main()
{
MyClass<int> cl(1, 2);
std::cout << cl << std::endl;
}
I have searched other questions but I couldn't find why exactly do I need:
template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);
the U instead of T in the typename? Because in the end U and T are both ints.
You can't use template <typename T> again because, on the rest of the line, it wouldn't know which of the two Ts you mean. It's kind of like this, which is also an error:
void foo(int x) {
int x = 4;
cout << x; // which x?
}
The compiler is not smart enough to figure out that in this case you will always want the two Ts to be the same, much like the error in the foo function above would not go away if you only ever called foo(4) in your program.
But what you've realized here is that you don't actually need the template arguments for operator<< at all here! That's because in this context you know exactly what type you want to use, whch is MyClass<T>. Normally, you can get rid of template parameters when you know the exact types you want. This is called an explicit specialization, and would normally look something like this:
template <>
friend std::ostream& operator<< <T>(std::ostream& os, const MyClass<T> &cl);
Note the empty template argument list template <>, which says "I don't need template arguments" and then the <T> after the function name, which says, "because I want the template argument type to be exactly T", where T is already known within a particular instantiation of the MyClass template. However this does not work here, because there is simply a rule in the C++ language specification that explicit specializations aren't allowed in friend declarations. (I am not exactly sure what the rationale is behind this rule, but it's a rule.)
So since you can't re-use the identifier T, and you can't explicitly specialize, the only option remaining is to use some other identifier, like U, for the template parameter.

Overloading addition operator inside a template class

I'm trying to write some code for simple complex number manipulation. I'm using a template class and I'm having trouble overloading operators (specifically +,-,*,/). I'm trying to declare the overload inside my template class, and then define them after in the same header file.
My header code is as follows:
#ifndef MY_CLASS_H
#define MY_CLASS_H
template <class T> class complex
{
private:
T re,im;
public:
// Constructors & destructor
complex(){re=im=0;}
complex(T r, T i){re=r; im=i;}
~complex(){}
// Return real component
T realcomp() const {return re;}
// Return imaginary component
T imagcomp() const {return im;}
// Overload + operator for addition
complex<T> operator+(const complex<T> &C);
....
};
#endif
#include<iostream>
#include<cmath>
using namespace std;
template <class T> complex<T>& complex<T>::operator+(const complex &C){
complex<T> A(re+C.realcomp(),im+C.imagcomp());
return A;
}
This returns errors that I have so far been unable to solve and I'm not entirely sure where I've gone wrong. A mixture of me being a beginner to C++ and trying to puzzle together solutions to other issues on this website has probably meant that my code is a bit of a mess - I apologise!
Any help would be greatly appreciated.
The declaration for complex<T>::operator+ is returning a complex<T> while the definition is returning a complex<T>&. You want to return the object by value, not reference.
Also, template classes must have their function definitions in the header file, since the compiler needs to be able to see these when instantiating the templates, so move the operator+ definition to the header file.
You should also use constructor initialization lists to initialize the member variables.
template <class T> class complex
{
private:
T re,im;
public:
// Constructors & destructor
complex() : re(), im() {}
complex( const T& r, const T& i ) : re(r), im(i) {}
~complex(){}
// Return real component
T realcomp() const {return re;}
// Return imaginary component
T imagcomp() const {return im;}
// Overload + operator for addition
complex<T> operator+(const complex<T> &C)
{
return complex<T>( re + C.realcomp(), im + C.imagcomp() );
}
};
You mismatched the declaration with the definition. Change this line:
template <class T> complex<T>& complex<T>::operator+(const complex &C){
to this
template <class T> complex<T> complex<T>::operator+(const complex &C){
(Note the missing "&")
This should work:
template <class T> complex<T> complex<T>::operator+(const complex<T> &C){
complex<T> A(re+C.realcomp(),im+C.imagcomp());
return A;
}
The return value is declared to be an object in the class and the patameter is missing the template parameter
you are returning a local variable as reference. plus the declaration are different:
you declare to return a complex while on definition you return a complex&

Friend functions of a class template

I have a class template Foo<T>.
I'd like to implement a non-member function Bar that takes two Foos and returns a Foo. I want Bar to be a non-member because it will be more natural for callers to write Bar(f1, f2) than f1.Bar(f2). I also want Bar to be inline because the calculation is trivial and frequent.
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
...
}
The trick is Bar needs access to Foo's private data. I'd prefer not to have accessors to the private data--there's no good reason to expose the private data to users. So I'd like to make Bar a friend of Foo.
template <typename T>
class Foo {
...
private:
T w, x, y, z;
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Here's where I run into trouble. The compiler complains:
The inline specifier cannot be used when a friend declaration refers to a specialization of a function template.
Is this rule imposed by the standard or is it specific to MSVC++?
Here's what I've tried:
Make Bar a const public member function, and then to declare a non-member version that simply returns lhs.Bar(rhs). This seems the least hacky solution.
Remove the inline hint, knowing that the compiler is going to decide about inlining regardless of the hint. Does this then run afoul of the one-definition rule? It will still have to be defined in a header file because it's a function template.
Declare the member function with a dummy template type:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
// Note that this declaration doesn't actually use Dummy. It's just there to
// satisfy the compiler.
template <typename Dummy>
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
I'm not entirely sure why that works, but it does satisfy the compiler.
Is there a better solution?
If the calculation is trivial, I would write:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
public:
friend Foo Bar(const Foo &lhs, const Foo &rhs) {
...
}
};
This doesn't fall foul of the ODR - it's an inline function with external linkage (3.2/5 excludes this from the ODR subject to the definitions being identical, 7.1.2/3 says that it's inline).
However, this doesn't define a function template Bar<T>, it just defines a set of function overloads for Bar. There may be some reason, unstated in the question, that means this won't work for you because you actually need the template.
I like option 1 the best:
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
return lhs.Bar(rhs);
}
template <typename T>
class Foo {
...
Foo<T> Bar(const Foo<T> &other) const;
private:
T w, x, y, z;
};
Then the functionality is safely contained within the class, but you provide a wrapper function for convenience.
Bar is a template, so it has to be a template in the friend declaration as well.
You don't necessarily have to use a dummy parameter, but could rather use
template <typename U>
friend Foo<U> Bar(const Foo<U> &lhs, const Foo<U> &rhs);
You cannot use T as the template parameter here, as there is already an outer T in scope.