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.
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.
For example, I have 2 structures: a 2D vector and a 3D vector with defined += operators:
struct Vector2
{
double x;
double y;
....
Vector2& operator+=(const Vector2& vector);
....
};
struct Vector3
{
double x;
double y;
double z;
....
Vector3& operator+=(const Vector3& vector);
....
};
It is trivial to implement '+' operators for these structures using the corresponding '+=' operators:
Vector2 operator+(const Vector2& vector1, const Vector2& vector2)
{
Vector2 result(vector1);
result += vector2;
return result;
}
Vector3 operator+(const Vector3& vector1, const Vector3& vector2)
{
Vector3 result(vector1);
result += vector2;
return result;
}
I'd like to unify these 2 functions and replace them with one template function:
template <class T>
T operator+(const T& vector1, const T& vector2)
{
T result(vector1);
result += vector2;
return result;
}
But this function is so general that it makes operator+ ambiguous for other classes.
I tried to make this template applicable only for Vector2 and Vector3 structs using custom type traits and static_assert:
template <class T>
T operator+(const T& vector1, const T& vector2)
{
static_assert(suitable_type_for_this_function<T>::value, "Unsupported type!");
...
}
But it does not hide declaration of the template operator for other classes. Therefore this approach again leads to ambiguity.
How can I implement such a unified operator+, but define it only for these 2 specific types?
template<class D>
struct add_using_increment {
using Self=add_using_increment<D>;
friend D operator+(Self&& lhs, Self const& rhs){
lhs+=rhs;
return std::move(lhs.self());
}
friend D operator+(Self const& lhs, Self const& rhs){
return D(lhs.self())+rhs;
}
private:
D&self(){ return *static_cast<D*>(this); }
D const&self()const{ return *static_cast<D const*>(this); }
};
Now just do this:
struct Vector2:add_using_increment<Vector2>
Altenratively you can use SFINAE to restrict your template argument to (A) being one of a fixed set, (B) having a void increment( lhs&, rhs const& ) function defined on it, (C) having a += defined on it.
(C) is too greedy.
You can also use boost.operators which is an industrial strength version of my add_using_increment.
You can apply SFINAE, use std::enable_if with std::is_same to constrain the types allowed on T.
template <class T>
std::enable_if_t<std::is_same_v<T, Vector2> || std::is_same_v<T, Vector3>, T>
operator+(const T& vector1, const T& vector2);
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.
In my code, I implement a template of Vector3 like below:
template <typename T>
struct TVector3{
TVector3(const T& x, const T& y, const T& z); // normal constructor from x,y,z
TVector3(const T& val); // construct from a constant value
// .. other implementation
T x, y, z;
};
// and my overload operator+ for TVector3
template <typename T>
const TVector3<T> operator+(const TVector3<T>& lhs, const TVector3<T>& rhs)
{
return TVector3<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
}
I'm expecting call like this: (1, 2, 3) + 1 = (2, 3, 4), so I wrote it like this:
TVector3<float> v(1, 2, 3);
v + 1.0f; // error, on operator "+" matches ... operand types are: TVector3<float> + float
Then I seem to understand that template deduction should completely match argument types instead of converting them, so is there any way for me to tell compiler to convert T to TVector3? I don't want to write 2 overloads like below because code would become large:
template <typename T>
const TVector3<T> operator+(const TVector3<T>& lhs, const T& rhs);
template <typename T>
const TVector3<T> operator+(const T& rhs, const TVector3<T>& rhs);
Thanks for helping!
The trick here is to instantiate a function that is not actually a member when the class template gets instantiated. This can be accomplished via a friend definition (inline friend). When the class template is instantiated, the friend is also instantiated, and also injected into the surrounding namespace (in a restricted way) as a non-templated function, so that conversions will be applied. (I also made the return non-const, since I don't think you intended that.) For further details, lookup "friend name injection", "argument dependent lookup", and the related Barton-Nackman trick.
template <typename T>
struct TVector3{
friend TVector3<T> operator+(const TVector3<T>& lhs, const TVector3<T>& rhs) {
return TVector3<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
}
TVector3(const T& x, const T& y, const T& z); // normal constructor from x,y,z
TVector3(const T& val); // construct from a constant value
// .. other implementation
T x, y, z;
};
int
main() {
TVector3<float> v(1, 2, 3);
v + 1.0f; // Works.
}
An important and related thing to note is that there is a difference between a template function and a non-template function, even if the signature is otherwise the same.
template <typename T> class A;
void f(A<int>); // 1
template <typename T>
void f(A<T>); // 2
template <typename T>
class A {
friend void f(A<T>); // Makes 1 a friend if T == int, but not 2.
friend void f<>(A<T>); /// Makes 2 also a friend.
};
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.