Overloading + Operator With Templates - c++

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.

Related

c++ inheritance: 2 times overloaded operator+ in base class are not working proper in derived class

I wrote my generic class "MyVector" based on std::valarray
//myvector.h
#ifndef MYVECTOR_H
#define MYVECTOR_H
#include <valarray>
template <typename T>
class MyVector
{
public:
MyVector(int size){larr.resize(size);}
MyVector<T>& operator=(const MyVector<T>& other)
{
this->larr=other.larr;
return *this;
}
MyVector<T> operator+ ( const MyVector<T>& rhs); //body in .cpp file
template <typename U>
MyVector<T> operator+ (const U& val); //body in .cpp file
protected:
std::valarray larr;
}
#endif
//myvector.cpp
/*****other code*****/
template <typename T>
MyVector<T> MyVector<T>::operator+ ( const MyVector<T>& rhs)
{
MyVector<T> lv; lv.larr = this->larr + rhs.larr;
return lv;
}
template <typename T>
template <typename U>
MyVector<T> MyVector<T>::operator+ (const U& val)
{
MyVector<T> lv; lv.larr = this->larr + static_cast<T> (val);
return lv;
}
/*****other code*****/
Then I try to write a derived class DataVector, with all the functions of MyVector, especially, all my overloaded operators.
#ifndef DATAVECTOR_H
#define DATAVECTOR_H
#include "myvector.h"
class dataVector : public MyVector<int>
{
public:
dataVector& operator=(const dataVector& other)
{
this->larr=other.larr;
return *this;
}
using MyVector<int>::operator=;
using MyVector<int>::operator+;
}
#endif
When I try to compile main.cpp,
//main.cpp
#include "datavector.h"
#include "myvector.h"
dataVector datav1(10);
dataVector datav2(10);
dataVector datav3(10);
//if i write:
datav1=datav1 + 10; //works (gmake and compiler gcc7.5 on ubuntu)
//if i write:
datav3=datav1 + datav2; //does not work (gmake and compiler gcc7.5 on ubuntu)
I obtain this compiler error:
myvector.cpp: In instantiation of ‘MyVector<T> MyVector<T>::operator+(const U&) [with U = dataVector; T = int]’:
myvector.cpp:xxx:yy: error: invalid static_cast from type ‘const dataVector’ to type ‘int’
MyVector<T> lv; lv.larr = this->larr + static_cast<T> (val);
If I use MyVector: MyVector3=MyVector1+MyVector2 works well.
Can anyone help me?
I know this code isn't well writed, but I'm still learning.
thank you.
The problem is that while when you add MyVector to MyVector, MyVector::operator+ ( const MyVector<T>& rhs) matches, but when you add dataVector to dataVector, dataVector::operator+ (const U& val) (inherited from MyVector) becomes a better match as it accepts anything, not necessarily something covertible to T. There are several possible solutions.
Make dataVector a typedef, like using dataVector = MyVector<int>, if suitable.
Add an operator+ accepting dataVector; it may call the inherited operator using an explicit cast (like *this + (const MyVector<int> &)rhs).
Restrict the MyVector::operator+ (const U& val) to accept T only, as suggested by Jarod42.
(The hard way) Restrict the MyVector::operator+ (const U& val) to accept sane types only using SFINAE (like template <typename U, typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>, or maybe is_convertible_to, or whatever appropriate).

templated function not found during compilation

I have a matrix class that supports operations with scalar values that I implemented using operator overloading. Since each overloaded operator function has the same body except for the operator being used, I decided to create a generic function that would accept a function along with the matrix and a scalar value to consolidate my code.
Here is the generic function and it being called from the overloaded addition operator function:
// Generic function to take care of matrix operations
template<typename T, typename F>
Matrix<T> scalar_operation(const Matrix<T> &a, const T b, F f) {
std::vector<std::vector<T> > new_els = a.elements;
typename std::vector<std::vector<T> >::iterator it = new_els.begin();
typename std::vector<T>::iterator it_in;
for (; it != new_els.end(); ++it) {
it_in = it->begin();
for (; it_in != it->end(); ++it_in) {
*it_in = f(*it_in, b);
}
}
return Matrix<T>(new_els);
}
// Add scalar to all values in Matrix
template<typename T>
Matrix<T> operator+(const Matrix<T> &a, const T b) {
return scalar_operation(a, b, std::plus<T>());
}
And here are the functions declared in the matrix class:
template<class T>
class Matrix {
template<typename F>
friend Matrix<T> scalar_operation(const Matrix<T> &a, const T b, F f);
friend Matrix<T> operator+<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator-<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator*<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator/<>(const Matrix<T> &a, const T b);
When I implemented the overloaded operator functions separately, they worked, but with this implementation, I get the following compiler error:
Undefined symbols for architecture x86_64:
"Matrix<float> scalar_operation<std::__1::plus<float> >(Matrix<float> const&, float, std::__1::plus<float>)", referenced from:
Matrix<float> operator+<float>(Matrix<float> const&, float) in matrix_test-3188cd.o
ld: symbol(s) not found for architecture x86_64
I imagine my error is related to the Matrix<float> scalar_operation<std::__1::plus<float> >( line because it looks like the linker is searching for a function with this header, which is slightly different from how it's declared in my file, but I've tried modifying my declaration and it throws additional errors.
Why am I getting this error and how can I fix it? Thanks!
EDIT: To clear up some confusion, all the code has been implemented in the header file since it is a templated class. There is no corresponding .cpp file.
The code has the following problem: class Matrix declares the friend function friend template<typename F> scalar_operation(...) (yes, friend keyword not only states the private access, it also declares a function), but there is no such function in outer scope. There is only the template<typename T, typename F> scalar_operation, that does not satisfy friend Matrix's declaration. Why? Let's try to pseudocode instantiations that can be made with float and std::plus<float> (return values and arguments omitted for shortness):
friend scalar_operation<std::plus<float>>(...)
and
scalar_operation<float, std::plus<float>>(...).
As we can see they are different. So during compilation we have no problem: we have proper friend scalar_operation declaration that satisfies calling convention inside operator+. But no definitions of such declaration can be made, and we get a problem while linking. The solution is a proper friend declaration:
template<typename TT, typename F>
friend Matrix<TT> scalar_operation(const Matrix<TT> &, const TT, F);

template operators fail seemingly on ambiguity

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);
^^^^^^^^^

Printing Vector on Console

I have a vector of type template class and I am trying to print it, but getting a weird error.
Here is my class:
template <typename VertexType, typename EdgeType> class Vertex{
private:
typedef std::vector<std::pair<int, EdgeType> > VertexList;
std::vector<Vertex<VertexType, EdgeType>> Vertice;
public:
void Add(Vertex);
};
Add Method and Print Statement:
template <typename VertexType, typename EdgeType> void Vertex<VertexType, EdgeType> ::Add(Vertex v)
{
int count = 5;
//std::vector<string>temp;
for(int i=0; i<count; i++)
Vertice.push_back(v);
for(int i=0; i<Vertice.size(); i++)
cout<< Vertice[i] <<endl;
}
Main() Method:
int main()
{
Vertex<std::string, std::string> v1;
v1.Add(v1);
std::getchar();
}
Error am getting is:
error C2679: binary '<<' : no operator
found which takes a right-hand operand
of type 'Vertex'
(or there is no acceptable conversion)
You aren't defining an operator << anywhere. You should define it like this out of your class :
template <typename VertexType, typename EdgeType>
std::ostream& operator << (std::ostream& out, const Vertex<VertexType,EdgeType>& v);
// implementation
template <typename VertexType, typename EdgeType>
std::ostream& operator << (std::ostream& out, const Vertex<VertexType,EdgeType>& v) {
// print whatever you want that represents your vertex
// please don't forget to return this reference.
return out;
}
Also, having a class with a vector of instances of it inside is a call for trouble. Remember that "vector<Vertice<VertexType,EdgeType> >" is an array of instances, not an array of references. If you want a array of 'references' to Vertex, use an array of pointers.
And consider using boost's graph library instead of redefining yet another one and coming to all pitfall associated with graphs (like memory management for instance). The boost library also have some useful algorithms that you could want to use..
Well, implement template <class V, class E> std::ostream& operator<<(std::ostream& os, const Vertex<V,E> &vertex) as a static friend of Vertex. It's pretty much what the compiler tells you...

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.,