I have a linking problem when using a home-made Complex class.
Class definition:
template<class T>
class Complex
{
public:
Complex(const T real = 0, const T imag = 0);
Complex(const Complex<T>& other);
~Complex(void) {};
Complex<T> operator*(const Complex<T>& other) const;
Complex<T> operator/(const Complex<T>& other) const;
Complex<T> operator+(const Complex<T>& other) const;
Complex<T> operator-(const Complex<T>& other) const;
friend void operator*=(const Complex<T>& z,const Complex<T>& other);
friend void operator/=(const Complex<T>& z,const Complex<T>& other);
friend void operator+=(const Complex<T>& z,const Complex<T>& other);
friend void operator-=(const Complex<T>& z,const Complex<T>& other);
void operator=(const Complex<T>& other);
friend T& real(Complex<T>& z);
friend T& imag(Complex<T>& z);
friend T abs(Complex<T>& z);
friend T norm(Complex<T>& z);
private:
T real_;
T imag_;
};
Implementation of abs:
template<class T>
T abs(Complex<T>& z)
{
return sqrt(z.real_*z.real_ + z.imag_*z.imag_);
}
I use the function abs like this : if(abs(z) <= 2).
Here are some errors I get:
Error 4 error LNK2001: unresolved external symbol "long double __cdecl abs(class Complex<long double> &)" (?abs##YAOAAV?$Complex#O###Z) C:\Users\Lucas\Documents\Visual Studio 2012\Projects\Fractals\Fractals\Main.obj Fractals
Error 3 error LNK2001: unresolved external symbol "long double & __cdecl imag(class Complex<long double> &)" (?imag##YAAAOAAV?$Complex#O###Z) C:\Users\Lucas\Documents\Visual Studio 2012\Projects\Fractals\Fractals\Main.obj Fractals
I get the same errors when using Complex<float> instead of Complex<long double>. I work with Visual C++ 2012. I would be really glad if you give me some hint on how to fix this. Thank you.
The function declared as
template <typename T>
class Complex {
// ...
friend T abs(Complex<T>& z);
// ...
};
is not a function template! It looks a bit like one as it is nested within a class template but that isn't quite enough. Here is what you probably meant to write:
template <typename T> class Complex;
template <typename T> T abs(Complex<T>&);
template <typename T>
class Complex {
// ...
friend T abs<T>(Complex<T>& z);
// ...
};
Alternatively, you could implement abs() when declaring it as friend.
Related
I have a linking problem when using a home-made Complex class.
Class definition:
template<class T>
class Complex
{
public:
Complex(const T real = 0, const T imag = 0);
Complex(const Complex<T>& other);
~Complex(void) {};
Complex<T> operator*(const Complex<T>& other) const;
Complex<T> operator/(const Complex<T>& other) const;
Complex<T> operator+(const Complex<T>& other) const;
Complex<T> operator-(const Complex<T>& other) const;
friend void operator*=(const Complex<T>& z,const Complex<T>& other);
friend void operator/=(const Complex<T>& z,const Complex<T>& other);
friend void operator+=(const Complex<T>& z,const Complex<T>& other);
friend void operator-=(const Complex<T>& z,const Complex<T>& other);
void operator=(const Complex<T>& other);
friend T& real(Complex<T>& z);
friend T& imag(Complex<T>& z);
friend T abs(Complex<T>& z);
friend T norm(Complex<T>& z);
private:
T real_;
T imag_;
};
Implementation of abs:
template<class T>
T abs(Complex<T>& z)
{
return sqrt(z.real_*z.real_ + z.imag_*z.imag_);
}
I use the function abs like this : if(abs(z) <= 2).
Here are some errors I get:
Error 4 error LNK2001: unresolved external symbol "long double __cdecl abs(class Complex<long double> &)" (?abs##YAOAAV?$Complex#O###Z) C:\Users\Lucas\Documents\Visual Studio 2012\Projects\Fractals\Fractals\Main.obj Fractals
Error 3 error LNK2001: unresolved external symbol "long double & __cdecl imag(class Complex<long double> &)" (?imag##YAAAOAAV?$Complex#O###Z) C:\Users\Lucas\Documents\Visual Studio 2012\Projects\Fractals\Fractals\Main.obj Fractals
I get the same errors when using Complex<float> instead of Complex<long double>. I work with Visual C++ 2012. I would be really glad if you give me some hint on how to fix this. Thank you.
The function declared as
template <typename T>
class Complex {
// ...
friend T abs(Complex<T>& z);
// ...
};
is not a function template! It looks a bit like one as it is nested within a class template but that isn't quite enough. Here is what you probably meant to write:
template <typename T> class Complex;
template <typename T> T abs(Complex<T>&);
template <typename T>
class Complex {
// ...
friend T abs<T>(Complex<T>& z);
// ...
};
Alternatively, you could implement abs() when declaring it as friend.
I'm trying to implement math library but I'm stuck on exporting. I have a template class for 2-dimensional vector:
vector2.h:
template <typename T>
class GE_API Vector2
{
public:
T x;
T y;
// Indexation
T& operator [] (const size_t i);
const T& operator [] (const size_t i) const;
bool operator == (const Vector2& v) const;
bool operator != (const Vector2& v) const;
// Negation
const Vector2 operator - () const;
// Assignement
const Vector2& operator = (const Vector2& v);
const Vector2& operator += (const Vector2& v);
const Vector2& operator -= (const Vector2& v);
template <typename S>
const Vector2& operator *= (const S& s);
template <typename S>
const Vector2& operator /= (const S& s);
const Vector2 operator + (const Vector2& v) const;
const Vector2 operator + (const T& s) const;
const Vector2 operator - (const Vector2& v) const;
const Vector2 operator - (const T& s) const;
template <typename S>
const Vector2 operator * (const S& s) const;
const Vector2 operator * (const Vector2& v) const;
template <typename S>
const Vector2 operator / (const S& s) const;
const Vector2 operator / (const Vector2& v) const;
};
template <typename T>
GE_API const T dot(const Vector2<T>& a, const Vector2<T>& b);
template <typename T>
GE_API const T length(const Vector2<T>& v);
//..and other functionality
#include <vector2.inl>
Definitions of operators and functions are in separate file vector2.inl which is included in header file. GE_API is standard dllimport/export macro. Problem is that when I try to export this class and functions defined in vector2.h header file I'm getting errors on definitions of operators that definition of dllimport function is not allowed. Why is that and how to fix this?
I think in this case you don't need to specify dllimport/export for your class.
Because all source code will be avaliable to the user and only anoe thing that he heeds is to include vactor2.h header into his project.
Any reason for the member functions "real" and "imag" in the std::complex class not to be const?
There are two overloads for real in the complex class template:
T real() const;
void real(T);
The first on is const, so that can't be what you're asking about.
The second one, which takes a T argument and returns nothing, is not const, because it's a "setter" method—the whole point of it is to change the state of the object, so it had better not be const.
Let's look at the C++ Standard:
C++ 2011 Section 26.4.2 Class Template Complex
namespace std {
template<class T>
class complex {
public:
typedef T value_type;
complex(const T& re = T(), const T& im = T());
complex(const complex&);
template<class X> complex(const complex<X>&);
T real() const;
void real(T);
T imag() const;
void imag(T);
complex<T>& operator= (const T&);
complex<T>& operator+=(const T&);
complex<T>& operator-=(const T&);
complex<T>& operator*=(const T&);
complex<T>& operator/=(const T&);
complex& operator=(const complex&);
template<class X> complex<T>& operator= (const complex<X>&);
template<class X> complex<T>& operator+=(const complex<X>&);
template<class X> complex<T>& operator-=(const complex<X>&);
template<class X> complex<T>& operator*=(const complex<X>&);
template<class X> complex<T>& operator/=(const complex<X>&);
};
}
I'd say that it's pretty clearly stated that std::complex::real() and std::complex::imag() are const methods.
I create a template class and want to overload an operator + (several times). I do this in the following way
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
....
template <typename T>
class Polynomial {
....
public:
....
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
friend const Polynomial<T> operator + <> (const Polynomial<T>& poly, const T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
However, I got the following error (which corresponds to the line that begins with 'friend')
problem2.cpp:282:45: error: declaration of ‘operator+’ as non-function
problem2.cpp:282:45: error: expected ‘;’ at end of member declaration
problem2.cpp:282:47: error: expected unqualified-id before ‘<’ token
Following Raxvan's advise, I've changed the code
template class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other);
....
template <typename T>
class Polynomial {
....
public:
....
friend ostream& operator << <> (ostream& out, const Polynomial<T>& other);
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
template <typename NOT_T>
friend const Polynomial<NOT_T> operator +(const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other) {
// implementation
}
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
And in this code I don't have problems with operator << as I had with operator +. Can anyone explain the defference?
The problem is subtle. Your syntax is very close to being
correct. I think your friend declaration should be:
friend Polynominal<T> const operator+<T>( ... );
but both VC++ and g++ accept:
friend Polynominal<> const operator+<T>( ... );
when they can see the declaration:
template <typename T>
const Polynomial<T> operator+(const Polynomial<T>& poly, const T& scalar);
(I can't find anything in the standard to justify this off hand,
but since both VC++ and g++ do it, I suppose that it's something
I've missed.)
And therein lies the problems. The declaration at namespace
scope of operator+ is hidden by the in-class definition. The
compiler complains because the operator+ it finds (the in
class definition) isn't a template itself (although it is
a member of a class template).
If you don't have the problem with operator<<, it's because
you don't have a member function with the same name.
There are several ways of solving this problem. The simplest is
probably to make all of the operator+ friends. Or not: the
most common approach to this is to implement operator+ in
terms of operator+= (which should be a member, in all cases).
In which case, operator+ doesn't have to be a friend.
Or you don't make operator+ a template at all, but definite it
inside your class template:
template <typename T>
class Polynomial
{
friend Polynomial operator+( Polynomial const& lhs, Polynomial const& rhs )
{
// ...
}
friend Polynomial operator+( Polynomial const& lhs, T const& rhs )
{
// ...
}
friend Polynomial operator+( T const& lhs, Polynomial const& rhs )
{
// ...
}
}
(Note that the functions being defined are not templates, but
separate overloaded non-template functions, one for each
instantiation of Polynomial. But the results end up being the
same.)
In this case, you probably would want to have a member function,
called by the operator+ functions, which would do the actual
work; you don't want too much code directly inline like this.
Your operator+ is a function template, to make this a friend, you need to declare it fully including the template parameters, however with a different template parameter, for example:
#include <iostream>
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
Polynomial operator +(const Polynomial& other) const {
std::cout << "inline +" << std::endl;
}
// Here introduce a different type to indicate that this is a template...
template <typename U>
friend const Polynomial<U> operator + (const Polynomial<U>& poly, const U& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
std::cout << "friend +" << std::endl;
}
int main(void)
{
Polynomial<int> f;
f = f + 1;
f = f + 1.; // this fails
f = f + Polynomial<int>();
}
You have to have the same definition when you label a function as friend, this includes the template used above with another type , not T
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
template < class NOT_T> //must respect the deffinition from above
friend const Polynomial<NOT_T> operator + (const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar)
{
//...
}
Edit:
For a simplified explanation i have changed the function to foo and bar to illustrate the difference in declarations:
template <typename T> class Polynomial;
template <typename T>
void bar(const Polynomial<T>& );
void foo(const Polynomial<float> & );//foo for speciffic float
template <typename T>
class Polynomial {
public:
template <typename> //this is also valid declaration;
friend void bar(const Polynomial<T> & );
//it just has to have template because it's a template functions declaration
//not a valid declaration:
//friend void bar <> (const Polynomial<T> & );
//this declaration has no template;
//it refers to a foo function specific to Polynomial<T> type
//so if you use Polynomial<float> there must be a foo for floats
friend void foo(const Polynomial<T> &);
};
template <class T>
void bar(const Polynomial<T>&)
{
}
void foo(const Polynomial<float> &)
{
}
void main()
{
Polynomial<float> pf;
Polynomial<int> pi;
foo(pi);//error since there is not **foo** declared for int
foo(pf);//ok; we have **foo** for Polynomial<float>
bar(pf);
bar(pi);//both ok since bar is templated function;
}
Raxvan.
I don't understand this link error.
I have 2 classes:
#include "Vector3.h"
#include "Quaternion.h"
template<typename T>
class Point3 final
{
public:
constexpr Point3(const Vector3<T>& vec)
: x(vec.x), y(vec.y), z(vec.z)
{}
constexpr operator const Vector3<T>() const
{
// It is the equivalent of Vector3 = Point3 - Origin
return Vector3<T>(x, y, z);
}
constexpr operator Vector3<T>() const
{
// It is the equivalent of Vector3 = Point3 - Origin
return Vector3<T>(x, y, z);
}
T x = T(0);
T y = T(0);
T z = T(0);
friend Vector3<T>;
friend Quaternion<T>;
friend Vector3<T> operator*( const Quaternion<T>& lhs, const Vector3<T>& rhs);
friend Vector3<T> operator*( Vector3<T> lhs, const Vector3<T>& rhs);
};
typedef Point3<Float32> Point3f;
and
template<typename T>
class Vector3 final
{
public:
constexpr Vector3()
{}
constexpr Vector3(T _x, T _y, T _z)
: x(_x), y(_y), z(_z)
{}
T x = T(0);
T y = T(0);
T z = T(0);
};
typedef Vector3<Float32> Vector3f;
I also have a Quaternion class the detail are irrelevant i beleive but this class has a non member operator*:
template<typename T>
Vector3<T> operator*( const Quaternion<T>& lhs, const Vector3<T>& rhs)
{
// nVidia SDK implementation
Vector3<T> qvec(lhs.x, lhs.y, lhs.z);
Vector3<T> uv = cross(qvec, rhs) * T(2.0) * lhs.w; //uv = qvec ^ v;
Vector3<T> uuv = cross(qvec, uv) * T(2.0); //uuv = qvec ^ uv;
return rhs + uv + uuv;
}
Now those line produce a link error, but why?
Math::Point3<Float32> pt = -Math::Point3<Float32>::UNIT_Z;
Math::Vector3<Float32> vec = orientation_*pt; // link error here (orientation is a Quaternion<Float32>)
//Math::Vector3<Float32> vec = orientation_*Math::Vector3<Float32>(pt); // this solve the link error.
Here is the link error
Undefined symbols for architecture x86_64:
Math::operator*(Math::Quaternion<float> const&, Math::Vector3<float> const&), referenced from:
GfxObject::Procedural::BoxGenerator::addToTriangleBuffer(GfxObject::Procedural::TriangleBuffer&) const in ProceduralBoxGenerator.o
Update
I found 2 question that are really close to this but the problem relies in the differences.
in:
question 1 and
question 2
But in my case I need to convert between 2 templates classes instead of the same class but 2 instantions. I hope this will help!
Try making sure the compiler knows your friend declaration is supposed to be a template specialization, not a declaration of a brand new non-template function:
friend Vector3<T> operator* <> (const Quaternion<T>& lhs, const Vector3<T>& rhs);
This common mistake is discussed in the C++ FAQ here.
Starting with an SSCCE:
template<typename T> class Quaternion { };
template<typename T> class Vector3 { };
template<typename T> class Point3 {
public:
operator Vector3<T>() const { return Vector3<T>(); }
friend Vector3<T> operator*( const Quaternion<T>& lhs, const Vector3<T>& rhs);
};
template<typename T>
Vector3<T> operator*(const Quaternion<T>& lhs, const Vector3<T>& rhs) { }
int main() {
Quaternion<float> orientation_;
Point3<float> pt;
Vector3<float> vec = orientation_*pt;
return 0;
}
Compiling that with gcc 4.7 I get the following:
x.cc:6:79: warning: friend declaration ‘Vector3<T> operator*(const Quaternion<T>&,
const Vector3<T>&)’ declares a non-template function
[-Wnon-template-friend]
x.cc:6:79: note: (if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Undefined symbols for architecture x86_64:
"operator*(Quaternion<float> const&, Vector3<float> const&)", referenced from:
_main in ccKgI7Ru.o
This points out the problem: you are declaring a friend function, not a friend template. To fix this, you have to do two things: make sure the template declaration preceedes this friendship line, and add angle brackets:
template<typename T>
Vector3<T> operator*(const Quaternion<T>& lhs, const Vector3<T>& rhs) { }
template<typename T> class Point3 {
public:
operator Vector3<T>() const { return Vector3<T>(); }
friend Vector3<T> operator*<>(const Quaternion<T>& lhs, const Vector3<T>& rhs);
};
This will turn the linker error into a compiler error:
error: no match for ‘operator*’ in ‘orientation_ * pt’
note: candidate is:
note: template<class T> Vector3<T> operator*(const Quaternion<T>&, const Vector3<T>&)
note: template argument deduction/substitution failed:
note: ‘Point3<float>’ is not derived from ‘const Vector3<T>’
Which makes sense: declaring a friend is a statement about who may access what data; it does not help a bit in automatic type conversions for template resolution. So I suggest the following instead:
template<typename T> class Point3 {
public:
operator Vector3<T>() const { return Vector3<T>(); }
friend Vector3<T> operator*(const Quaternion<T>& lhs, const Point3& rhs) {
return lhs * Vector3<T>(rhs);
}
};
This declares a new inline friend operator, which will explicitely do the cast you had intended.
Actually to make it work i have to give a body to the friend declared function in the Point class. I wanted to do like item 46 of Effective C++ (3rd edition) from Scott Meyers. like in this question, link.
The key is that the function inside have to have a body. so the class Point3 now become (I have stripped some useless code like MvG did, thanks.
template<typename T> class Point3 {
public:
operator Vector3<T>() const { return Vector3<T>(); }
friend Vector3<T> operator*( const Quaternion<T>& lhs, const Vector3<T>& rhs)
{
return lhs*rhs;
}
};
This make everything compiles and link.
lhsrhs will call the operator defined in Quaternion.h ( that is included in the header file of Point3).
What i don't understand is why i don't have duplicated symbol.
To me the friend operator* inside the Point3 class and the operator* defined in the Quaternion.h header file are the same signature and yet it compile and links.