Exporting templated inline functions - definition of function dllimport not allowed - c++

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.

Related

Unified implementation of c++ '+' operator using '+=' operator

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

C++ template functions

This Vec template supports several functions such as multiplying a vector by scalar and adding vector to another vector.
The thing that is confusing me is that why the overloading of the second operator* is outside of the class template?
The operator* which is declared in the class overloads vectorXscalar
The one declared outside supports scalarXvector
template <class T>
class Vec {
public:
typename list<T>::const_iterator begin() const {
return vals_.begin();
}
typename list<T>::const_iterator end() const {
return vals_.end();
}
Vec() {};
Vec(const T& el);
void push_back(T el);
unsigned int size() const;
Vec operator+(const Vec& rhs) const;
Vec operator*(const T& rhs) const; //here
T& operator[](unsigned int ind);
const T& operator[](unsigned int ind) const;
Vec operator,(const Vec& rhs) const;
Vec operator[](const Vec<unsigned int>& ind) const;
template <class Compare>
void sort(Compare comp) {
vals_.sort(comp);
}
protected:
list<T> vals_;
};
template <class T>
Vec<T> operator*(const T& lhs, const Vec<T>& rhs); //and here!
template <class T>
ostream& operator<<(ostream& ro, const Vec<T>& v);
The operator* declared inside the template class could equally be written outside the class as
template <class T>
Vec<T> operator*(const Vec<T>& lhs, const T& rhs);
It can be written inside the class with a single argument (representing the rhs) because there is the implied *this argument used as the lhs of the operator.
The difference with the operator* defined outside the class is that the lhs of the operator is a template type. This allows the arguments to be supplied either way around when using the operator.
You are allowed to define the operator outside of a class with any arbitrary lhs and rhs types, but within the class are restricted to only varying the rhs. The compiler would select the best match of any defined operator* given the argument types.

Why is std::complex real member function not const?

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 don't understand this link error

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.

How to resolve ambiguous operator in ISO C++

I'm pretty much out of ideas now with porting a big bunch of old C++ code from MS Visual C++ 7.0 to iOS 4 iPhone g++ 4.2.1 compiler. I get some ambiquity errors compiling this:
complex_d* cp;
complex_d qSt;
double zi;
// complex_d += complex_d * double
*cp += qSt * dVal; // ISO C++ says that these are ambiguous
with the class definition of complex_d as:
#include <math.h>
#include "CObject.h" // emulated MFC class, used for some types like BOOL
#include "CString.h" // emulated MFC class, also needed for some types not on iOS
// interface for complex calculations
//
/////////////////////////////////////////////////////////////////////////////
class polar_d; // forward declaration
class complex_d
{
// attributes
protected:
double re;
double im;
// construction
public:
complex_d(double re = 0, double im = 0);
complex_d(const complex_d& x);
virtual ~complex_d() { };
// implementation
public:
double real(void) const;
double imag(void) const;
double& setReal(void); // needed because we don't have Serialize() here
double& setImag(void); // as above
double Abs(void) const;
double Phi(void) const;
complex_d Conjugate(void);
polar_d Polar(void);
BOOL IsZero(void) const;
BOOL IsReal(void) const;
BOOL IsImag(void) const;
complex_d& operator=(const complex_d& rhs);
complex_d& operator+=(const complex_d& rhs);
complex_d& operator-=(const complex_d& rhs);
complex_d& operator*=(const complex_d& rhs);
complex_d& operator/=(const complex_d& rhs);
complex_d operator+(const complex_d& rhs);
complex_d operator-(const complex_d& rhs);
complex_d operator*(const complex_d& rhs); // ambiguous error here...
complex_d operator/(const complex_d& rhs);
complex_d operator-(void); // unary
complex_d& operator=(const double& rhs);
friend complex_d operator+(const complex_d& lhs, double rhs);
friend complex_d operator+(double lhs, const complex_d& rhs);
friend complex_d operator-(const complex_d& lhs, double rhs);
friend complex_d operator-(double lhs, const complex_d& rhs);
friend complex_d operator*(const complex_d& lhs, double rhs); // ... and here also ambigous
friend complex_d operator*(double lhs, const complex_d& rhs);
friend complex_d operator/(const complex_d& lhs, double rhs);
friend complex_d operator/(double lhs, const complex_d& rhs);
friend BOOL operator==(const complex_d& lhs, double rhs);
friend BOOL operator==(double lhs, const complex_d& rhs);
friend BOOL operator!=(const complex_d& lhs, double rhs);
friend BOOL operator!=(double lhs, const complex_d& rhs);
friend BOOL operator==(const complex_d& lhs, const complex_d& rhs);
friend BOOL operator!=(const complex_d& lhs, const complex_d& rhs);
};
The two operators in question are marked as ambigous but I don't see why. Originally this class was written as a template which in fact only was instantiated with double type. So I de-templated the complex_d class which results in the definition above. It compiled w/out errors and warnings in MSC environment using MS Visual C++ .NET 2002 but I get these ambiguity errors with g++ 4.2.1 now.
I'm quite long off writing code with overloading operators in C++ and I experimented a lot rewriting the two definitions of the * operators. The main problem is I don't understand why this is ambiguous. For:
qSt * dVal
a complex_d has to be multiplied with a double variable value and the result has to be returned as complex_d. Therefore the friend operator * has to be evaluated. When I replace the operator
friend complex_d operator*(const complex_d& lhs, double rhs);
with
complex_d operator*(double rhs);
I get another error telling me that a class member or enum is needed as parameter. It is also not possible to omit the second operator in question because it is also needed at another place in the code.
Is anyone out there who can tell me how to get out of this dilemma?
I see two ways to fix this (there's probably more):
Add explicit to the constructor:
explicit complex_d(double re = 0, double im = 0);
Remove the friend operator*().
The C++ std::lib went with solution #2 for std::complex.