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&
Related
I was looking at the <complex> implementations of the C++ Standard Library. I noticed for all of the current GNU, LLVM and MSVC implementations, there is a huge amount of code duplication for template specializations for types float double and long double, but I don't know why.
Take the MSVC code at https://github.com/microsoft/STL/blob/main/stl/inc/complex as an example, consider the class template and its specializations
template <class _Ty>
class complex;
template <>
class complex<float>;
template <>
class complex<double>;
template <>
class complex<long double>;
There are already definitions in the general class template. Take one definition for operator*= as an example,
template <class _Ty>
class complex : public _Complex_base<_Ty, _Complex_value<_Ty>> {
public:
// ...
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
this->_Val[_RE] = this->_Val[_RE] * _Right;
this->_Val[_IM] = this->_Val[_IM] * _Right;
return *this;
}
// ...
};
Why is this kind of code repeated again and again for almost all member functions in the specializations for float double and long double as below?
template <>
class complex<double> : public _Complex_base<double, _Dcomplex_value> {
public:
// ...
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
_Val[_RE] = _Val[_RE] * _Right;
_Val[_IM] = _Val[_IM] * _Right;
return *this;
}
// ...
};
What is the reason for such code duplication in the template specializations for std::complex<T>?
For reference, in the above MSVC code, it is
using _Dcomplex_value = _CSTD _C_double_complex;
For reference, the GNU implementation of <complex> can be found at https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/complex
For reference, the LLVM implementation of <complex> can be found at https://github.com/llvm/llvm-project/blob/main/libcxx/include/complex
For reference, the MSVC implementation of <complex> can be found at MSVC code at https://github.com/microsoft/STL/blob/main/stl/inc/complex
What is the reason for such code duplication
Short answer: return *this
You need to have each operator defined in the specializations in order to be able to return the correct type. Otherwise they would return references to the base class.
You could call the base class operator in the derived class, like
_CONSTEXPR20 complex& operator*=(const _Ty& _Right) {
_Complex_base<_Ty, _Complex_value<_Ty>>::operator*=(_Right);
return *this;
}
but, even though is reduces repetition it really doesn't reduce the code size, or make it any more readable.
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);
}
I'm looking for an elegant way (defined by minimal repeated code) to overload an operator to do the following:
I have a template class BaseSignal which overloads the += operator, and I would like to be able to accept many different types. For example, for a double, the code looks like
template <class T>
class BaseSignal
{
public:
....
// Self-increment
BaseSignal<T>& operator+=(const double& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
....
What I've been doing is repeating this body of code for int, long, etc. Since the value rhs is only used in the line static_cast<T>(rhs), I am repeating code while only changing the input parameter type.
So I could template this, e.g.
template <class T, class U>
class BaseSignal
{
public:
....
// Self-increment
BaseSignal<T>& operator+=(const U& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
....
But then it looks like I lose the "overloading" aspect in that the compiler would automatically select the correct method for me (it would also only work for the original U type that was instantiated).
I realize that I am trying to achieve some untyped language behavior with C++, which may not be the smartest thing, I am just trying to add some intelligence to a few commonly-used classes so that subsequent code will become much easier to write.
Thank you in advance.
You might do
template <class T>
class BaseSignal
{
public:
// Self-increment
template <class U>
BaseSignal<T>& operator+=(const U& rhs)
{
T rval;
this->Get(&rval);
this->Set(rval + static_cast<T>(rhs));
return *this;
}
};
Is it considered a good practice to use friend to define global functions within the class definition, even when the access to private members is not needed. For example
template<typename T>
class A {
public:
A(T v);
T value() const;
friend A operator+(T n, const A& a) {
return A(a.value() + n);
}
};
instead of
template<typename T>
class A {
public:
A(T v);
T value() const;
};
template<typename T>
A<T> operator+(T n, const A<T>& a) {
return A<T>(a.value() + n);
}
even though operator+ only uses value() which is public.
Is this commonly done, us is it not recommended?
There's one major advantage to friend here. When we define:
friend A operator+(T, const A&);
This is not a function template. This is just a function - a special one that can only be found by ADL. But since it's not a function template, conversions still can happen. On the flip side:
template <class T>
A<T> operator+(T, const A<T>&)
is a normal old function template with all of the normal rules regarding template type deduction.
Why does this matter? Consider:
A<double> a(4.2);
5 + a;
In the first case, this is perfectly fine. We find operator+(double, const A<double>&), the 5 gets converted to 5.0, which is an allowed conversion, and we get back A<double>(9.2).
In the second case, template deduction fails because the T deduces to different types for the two arguments. Hence, the code is ill-formed.
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.