template operators fail seemingly on ambiguity - c++

This is not a duplicate. I've checked lots of answers, the FAQ and else. Nothing of that told me news. Here is the simplified code. It's the minimum to get and explain the error.
/*** Polynomial.hpp ********************************************************/
namespace Modulus
{
// Forward declaration of the types and non-inline template friend functions.
template <typename T>
class Polynomial;
template <typename T>
Polynomial<T> operator +
(Polynomial<T> const & p,
Polynomial<T> const & q);
}
namespace Modulus
{
template <typename T>
class Polynomial
{
public:
Polynomial() { }
// [!] when you comment this in, you get the error.
//Polynomial operator + () const { return *this; }
friend Polynomial operator + <> (Polynomial const & p,
Polynomial const & q);
};
} // namespace
// Template: include .cpp file.
//#include "Polynomial.cpp"
///^ It is commented out, for compiling in one file.
/*** Polynomial.cpp ********************************************************/
namespace Modulus
{
template <typename T>
Polynomial<T>
operator + (Polynomial<T> const & p,
Polynomial<T> const & q)
{
return Polynomial<T>();
}
} // namespace
/*** main.cpp **************************************************************/
//#include "Polynomial.hpp"
using namespace Modulus;
int main()
{
Polynomial<int> p;
p + p;
return 0;
}
When I comment the line under [!] in, the error I get is friends can only be classes or functions (Clang++) or declaration of ‘operator+’ as non-function (g++).
For me, it seems the compilers mistake the two operators. As far as I've learned the operator overloading stuff, the unary and binary operators are completely independent and can be uniquely distinguished by their number of arguments.
So why does the error occur? Making the unary operator a friend using the standard practice, makes the code compile fine on both compilers.

When you declare something in a scope, it hides delcarations of the same name in any wider scope. Here, the declaration of the member operator+ hides that of the non-member. So the friend declaration refers to the member, not the non-member, hence the error.
You'll need to qualify the name if you want to refer to both in the same scope:
Polynomial operator + () const { return *this; }
friend Polynomial Modulus::operator + <> (Polynomial const & p, Polynomial const & q);
^^^^^^^^^

Related

operator overloading using template

I'm writing a class named Double which extends the built in type 'double' in c++. It has a data member of the type 'double'. For the class Double I need to overload many basic arithmetic operators like "+", "-", "*", "/". For example, the "+" operator is overloaded this way:
Relation<Double>* operator+ (Double &d2)
// Relation is a abstract class template.
{
/*
...code that do something else.
*/
return new Plus<Double>(this, &d2); // Plus is derived from Relation.
}
// Double + Double returns a Relation pointer.
and the "-" operator is overloaded fast the same way:
Relation<Double>* operator- (Double &d2)
{
/*
...code that do something else but the same as above.
*/
return new Minus<Double>(this, &d2);
}
The actual calculation is done by the member function in the Relation class. The only difference of the operators' bodies is the object initialized(Plus vs Minus).
For operator that takes exactly two operands, I should alway do the overloading like this, which is duplicated and not nice.
So template function comes to my mind. But the problem is, I can pass Plus or Minus as template argument, but can not pass the operator. How could I make a template or use other methods to do the overloading of these operators?
Yes, operator overloading may be a pain and source of code duplication, see this suggestion to the standard to ease it.
For now the only I can think about is something like this:
template<typename T>
struct OperatorMinus {
static T doIt(T const& lhs, T const& rhs) { return lhs - rhs; };
}
template<typename T>
struct OperatorPlus {
static T doIt(T const& lhs, T const& rhs) { return lhs + rhs; };
}
template<typename T, typename U>
class Operator: public Relation<T>
public:
Operator(T const& lhs, T const& rhs): _lhs(lhs), _rhs(rhs) {}
T doIt() override {
return U::doIt(_lhs, _rhs);
}
private:
T _lhs;
T _rhs;
};
Relation<Double>* operator+ (Double &d2)
{
return new Operator<Double, OperatorPlus<Double>>(this, &d2);
}

C++ template operator overloading with different types

The example below defines a basic podtype container class. Using this class a series of typedefs are then created which represent an OOP version of the basic podtype. The problem originates when we start assigning those types to one another.
I tried to define the operator as friend method with lhs and rhs arguments using plain PodObjects as type but without any succes. Is there anyone who might have experienced something simular or knows an other solution for this problem.
Thanks in advance.
#include <stdint.h>
template <typename T>
class PodObject {
protected:
T _value;
public:
PodObject<T>(int rhs) {
this->_value = static_cast<T>(rhs);
}
PodObject<T> operator+= (PodObject<T> const &rhs){
this->_value = rhs._value;
return *this;
}
};
typedef PodObject<int8_t> Int8;
typedef PodObject<int16_t> Int16;
int main() {
Int16 a = 10;
Int8 b = 15;
a += b; // Source of problem
return 0;
}
Results in a compiler output:
example.cpp:26:11: error: no viable overloaded '+='
a += b;
~ ^ ~
example.cpp:13:22: note: candidate function not viable: no known conversion from 'Int8' (aka 'PodObject<int8_t>') to 'const PodObject<short>'
for 1st argument
PodObject<T> operator+= (PodObject<T> const &rhs){
EDIT:
The friend method below does the job for me:
template<typename U, typename W>
friend PodObject<U> operator+= (PodObject<U> &lhs, PodObject<W> const &rhs) {
lhs._value += rhs._value;
return lhs;
}
You need a templated operator + because you are trying to add different types:
template <typename U>
PodObject<T> operator+= (PodObject<U> const &rhs){
this->_value = rhs._value;
return *this;
}
That said, the whole code looks like an anti-pattern. Your “OOP version of the basic podtype” is not a meaningful, nor generally useful, concept.

C++ Automatic constructor call on template operator overload?

I have the following in my header file:
template<typename T>
class rational {
private:
T num;
T denom;
T gcd(T x, T y);
public:
rational(T num, T denom);
rational(T wholeNumber);
template<typename U>
friend inline rational<U> operator *(const rational<U> &lhs, const rational<U> &rhs);
}
template<typename T>
rational<T>::rational(T whole) {
this->num = whole;
this->denom = 1;
}
template<typename T>
rational<T> operator *(const rational<T> &lhs, const rational<T> &rhs) {
return rational<T>(lhs.num * rhs.num, lhs.denom * rhs.denom);
}
And the following in my main:
rational<int> x(6), y(2);
rational<int> product = y * x; // this works
rational<int> product2 = 2 * x; // this doesn't
The first product works, but the second one gives me "error: no match for ‘operator*’ in ‘2 * x’". Why? Since there is a constructor available that takes only the 2 as an argument, shouldn't that be automatically called? If not, how else would I overload the operator to have both of these work?
Thanks.
I'm not sure why the compiler will not invoke the single-argument constructor implicitly on 2 in order to produce a rational, but my guess is that the inference mechanism is simply broken when templates are involved.
One workaround (if no one knows how to fix the implicit constructor issue) is to define an additional multiply operators like thus:
template<typename T>
rational<T> operator *(const T &lhs, const rational<T> &rhs) {
return rational<T>(lhs * rhs.num, rhs.denom);
}
template<typename T>
rational<T> operator *(const rational<T> &lhs, const T &rhs) {
return rational<T>(lhs.num * rhs, lhs.denom);
}
This will also perform better, if you are writing high-performance code using rationals in an inner loop somewhere.
2 * x;
is analogical equivalent to calling of,
int::operator*(const rantional<int>&)
2 is an int and it doesn't have operator * overloaded for const rational<int>&; thus you get compiler errors.
The correct way is to have:
rational<int> product2 = rational<int>(2) * x; // ok

Overloading + operator on generic class in C++

I'm trying to overload the + operator in a forest class, a forest being a collection of trees, and the + operator is supposed to combine two forests into one. I have the following code as my class definition:
template<typename NODETYPE>
class Forest
{
public:
friend Forest& operator+<>(Forest&, Forest&);
friend ostream& operator<<<>(ostream&, const Forest&);
friend istream& operator>><>(istream&, Forest&);
Forest();
Forest( const Forest& otherForest);
~Forest();
void nodes(int&) const;
private:
ForestNode<NODETYPE> *root;
ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};
The following is my implementation of operator+:
template<typename NODETYPE>
Forest& operator+<>(Forest& f1, Forest& f2)
{
f3 = new Forest();
f3.root = *f1.*root;
f3.root.sibling = *f2.*root;
*f1.root = 0;
*f2.root = 0;
return f3;
}
I get the following error on compile:
|28|error: expected constructor, destructor, or type conversion before '&' token|
line 28 refers to the signature of my operator+ implementation.
I think to correct it i am supposed to add to the return type, giving:
template<typename NODETYPE>
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2)
{
f3 = new Forest();
f3.root = *f1.*root;
f3.root.sibling = *f2.*root;
*f1.root = 0;
*f2.root = 0;
return f3;
}
But that gives me the following errors:
|28|error: declaration of 'operator+' as non-function|
|28|error: missing template arguments before '&' token|
|28|error: 'f1' was not declared in this scope|
|28|error: missing template arguments before '&' token|
|28|error: 'f2' was not declared in this scope|
Can anyone help me with this? I'd be very very thankful.
The key to writing operator+ is don't write operator+. Instead, write a copy ctor and operator+=:
template<class NodeType>
struct Forest {
//...
Forest(Forest const &other);
//...
Forest& operator+=(Forest const &other) {
// code here
return *this;
}
//...
};
Now we add operator+:
template<class NodeType>
struct Forest {
//...
friend Forest operator+(Forest a, Forest const &b) {
a += b;
return a;
}
//...
};
And that's it! Copying is usually straight-forward (sometimes by being disallowed) and it may be simpler to think in terms of += than + (you have two objects and mutate one, rather than create a third object out of two). This pattern for op+ works with any similar type, and even for similar operators such as -, *, and /.
Operator overloading can be a good or a bad thing. Good when it leads to simpler looking code. Bad when it leads to writers either overloading with incorrect semantics (yet a solution that compiles) or where the intuitive way to use the operator leads to highly inefficient code.
Note the latter statement can apply to std::string too, which could potentially make large numbers of copies, and which is why the C++03 standard states that a string does not have to be stored internally in a contiguous buffer (in the old days they used copy-on-write references to and could store such references to both strings being concatenated until required. Subsequently it was found to be non-threadsafe and making it so was more costly than simply copying the buffer so now they copy every time and are inefficient again).
(Note that the C++11 standard which recognises threading and atomic issues ensures that the underlying does need to be contiguous and null-terminated to make read operations safe).
The correct signature of operator+ (in the case all are the same type) is as follows:
T operator+( const T&, const T& );
As a member function it would be:
class T
{
// make public if necessary
T operator+( const T& rhs ) const;
};
You can implement operator+ automatically as a template whenever operator += is available with
template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
T copy(lhs);
return copy += rhs;
}
If you want to declare an overloaded operator of your template as a friend, this is the correct way to do it. I will show it with operator<<
// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum
template< typename T > class Forest;
template< typename T > std::ostream & operator<<( std::ostream & os, const Forest<T> & for );
template< typename T> class Forest
{
friend std::ostream& operator<< <>( std::ostream&, const Forest<T> & );
//rest of class Forest
};
template< typename T >
std::ostream & operator<<( std::ostream& os, const Forest<T> & forest )
{
// implement
return os;
}
You would apply a similar technique to any other external function you wish to declare as a friend to your class, i.e.
Forwardly declare your class as a template
Forwardly declare the method as a template function
Make the function a friend using <> before the opening parentheses denoting the parameters
Implement the function after your class.
You have to provide a template arguments for all Forest parameters.
template<typename NODETYPE>
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2)
Also, consider making the arguments const references to make sure you do not manipulate them.
There are several questions on stackoverflow regarding friend function templates. The C++ FAQ also has a page on them that explains some basics.
You can define an operator+ template as follows:
template< class NodeType >
Forest<NodeType> operator+( Forest<NodeType> const& f1, Forest<NodeType> const& f2)
{
// Implementation.
}
Cheers & hth.,

Overloading + Operator With Templates

Hey, I'm getting a linker error LNK2019: unresolved external symbol when trying to use an overloaded + operator. I'll show you snip-its from the class, and how I'm using it in main. If you need to see more, let me know, I'm just going to try and keep things concise.
/** vec.h **/
#ifndef __VEC_H_
#define __VEC_H_
#include <iostream>
#include <vector>
namespace xoor{
template<typename T>
class vec{
public:
inline friend vec<T> operator + (const vec<T>&, const vec<T>&);
inline const vec<T>& operator += (const vec<T>&);
private:
std::vector<T> m_index;
}; // Vec.
template<typename T>
vec<T>& operator + (const vec<T>& a, const vec<T>& b){
vec<T> product = a;
product += b;
return product;
} // Addition.
template<typename T>
const vec<T>& vec<T>::operator += (const vec<T>& v){
for (unsigned short i =0; i < m_index.size(); ++i){
if (i >= v.size())
break;
m_index[i] += v.getIndex()[i];
}
return * this;
} // Addition Compound.
} // xoor
#endif // __VEC_H_
Note that I've got [] overloaded as well, so I'm just accessing parts of m_index with it. getIndex() just returns m_index. And size() returns m_index.size()
/** main.cpp **/
#include <iostream>
#include "vec.h"
void testHook();
int main(){
testHook();
system("PAUSE");
return 0;
}
void testHook(){
using namespace xoor;
vec<double> vA(3); // passing 3 for 3 elements
vec<double> vB(3);
// v + v
std::cout << "\n\tA + B = ";
vec<double> vAB(3);
vAB = vA + vB; // PRODUCES THE LNK2019
vAB.print(std::cout); // Outputs the vec class to the console.
}
Error Message:
Error 1 error LNK2019: unresolved external symbol "class xoor::vec<double> __cdecl xoor::operator+(class xoor::vec<double> const &,class xoor::vec<double> const &)" (??Hxoor##YA?AV?$vec#N#0#ABV10#0#Z) referenced in function "void __cdecl testHook(void)" (?testHook##YAXXZ) main.obj
Update:
The following is now directly above the class definition. I continue to get the same linker error, as described above.
template<typename T>
class vec;
template<typename T>
vec<T> operator + (const vec<T>&, const vec<T>&);
Update 2: Solution.
The above update is incorrect. sbi's solution did work, I just failed to template the operator as follows.
template<typename T>
vec<T> operator +<T> (const vec<T>&, const vec<T>&);
sbi, and david were discussing why I was using friends in the first place. Initially I was using them, because you can not pass two parameters to an overloaded binary operator such as +, and immediate sought after friends as the solution. As it turns out, you can still use the binary operator quite easily with a single parameter. Here is the final solution.
// ...
template<typename T>
class vec{
public:
const vec<T> operator + (const vec<T>&, const vec<T>&)const;
// ...
}; // Vec.
template<typename T>
const vec<T> vec<T>::operator + (const vec<T>& v)const{
matrix<T> product = *this;
vec(product += v);
} // Addition.
Also, for anyone else reading this, its worth while to check out sbi's notes at the bottom of his answer. There are some things I've been doing that are superfluous.
Thanks for the help everyone. Happy coding.
In order to befriend a template, I think you'll need to declare that template before the class definition in which you want to befriend it. However, for this declaration to compile, you'll need to forward-declare the class template. So this should work:
template<typename T>
class vec;
template<typename T>
vec<T> operator + (vec<T>, const vec<T>&);
template<typename T>
class vec{
public:
friend vec<T> operator +<T> (vec<T>, const vec<T>&);
// ...
This befriends a specific instance of the operator+() function template, namely operator+<T>. (You can also befriend all instances of a template:
// no forward declarations necessary
template<typename T>
class some_class {
template<typename U>
friend void f(vec<U>&);
// ...
};
However, that's less often useful than the other one.)
Edit: A comment by David got me thinking (should've done this from the beginning!) and that lead to the discovery that the friend declaration is unnecessary. Your operator+ is only using one public member function of vec (operator+=) and thus doesn't need to be a friend of the class. So the above would simplify to
template<typename T>
class vec{
public:
// ...
};
template<typename T>
vec<T> operator + (vec<T> a, const vec<T>& b){
a += b;
return a;
}
Here's a few more notes:
operator+() (which you nicely implemented on top of operator+=(), BTW) should take its left argument per copy.
Don't declare functions as inline, define them so.
Have operator+=() return a non-const reference, because everybody expects f(m1+=m2) to work even if f() takes its argument as a non-const reference.
Inside of a class template, in most places you can omit the template parameter list when refering to the class. So you can say vec& operator += (const vec&);. (You cannot do this outside of the template, though - for example, when defining that operator outside of the class.)
A std::vector's index type is spelled std::vector<blah>::size_type, not unsigned short.
The return type here:
inline friend vec<T> operator + (const vec<T>&, const vec<T>&);
Does not match here:
template<typename T>
vec<T>& operator + (const vec<T>& a, const vec<T>& b){
vec<T> product = a;
product += b;
return product;
} // Addition.