Issues with adding templated and/or overloaded operators


#1

I have a C++ Vector class in my program. It is a templated class which takes <T, unsigned> as its arguments (data type and dimension). I then use typedefs to define the most common types, like so:

typedef Vector<bool, 3> Vector3f;
typedef Vector<int, 3> Vector3i;
typedef Vector<float, 3> Vector3f;
typedef Vector<unsigned, 3> Vector3u;

All operators except for [] and = are implemented as templated free functions to reduce code duplication. I am trying to expose these classes to ChaiScript. Below is an example of a partial Vector3f hookup to ChaiScript.

ModulePtr vec3fClass(new Module());
vec3fClass->add(user_type<Math::Vector3f>(), "Vector3f");
vec3fClass->add(constructor<Math::Vector3f()>(), "Vector3f");
vec3fClass->add(constructor<Math::Vector3f(float)>(), "Vector3f");
vec3fClass->add(constructor<Math::Vector3f(float, float, float)>(), "Vector3f");
vec3fClass->add(constructor<Math::Vector3f(const Math::Vector3f&)>(), "Vector3f");
vec3fClass->add(fun(&Math::Vector3f::data), "data");
vec3fClass->add(fun(&Math::Vector3f::x), "x");
vec3fClass->add(fun(&Math::Vector3f::y), "y");
vec3fClass->add(fun(&Math::Vector3f::z), "z");
vec3fClass->add(fun(&Math::Vector3f::toString), "toString");
vec3fClass->add(fun(&Math::Vector3f::operator=), "=");
vec3fClass->add(fun(&Math::Vector3f::operator[]), "[]");
vec3fClass->add(fun(&Math::operator!<float, 3>), "!");
vec3fClass->add(fun(&Math::operator==<float, 3>), "==");
vec3fClass->add(fun(&Math::operator!=<float, 3>), "!=");
vec3fClass->add(fun(&Math::operator><float, 3>), ">");
vec3fClass->add(fun(&Math::operator>=<float, 3>), ">=");

So far so good. But two problems arise when I try to add the rest of the operators.


##1. Overloaded and templated operators

I am running into issues when binding operators that have multiple versions of them. Take operator+ for example:

// Promote all vector components (make positive)
template <typename T, unsigned n>
Vector<T, n> operator +(const Vector<T, n>& right);

// Add two vectors of the same type
template <typename T, unsigned n>
Vector<T, n> operator +(const Vector<T, n>& left, const Vector<T, n>& right);

// Add a vector and a scalar (same type)
template <typename T, unsigned n>
Vector<T, n> operator +(const Vector<T, n>& vector, const T& scalar);

// Add a scalar and a vector (same type)
template <typename T, unsigned n>
Vector<T, n> operator +(const T& scalar, const Vector<T, n>& vector);

As you can see, operator+ is a heavily overloaded function. So when I try to do this:

vec3fClass->add(fun(&Math::operator+<float, 3>), "+");

I get the following error:

error: no matching function for call to 'fun(<unresolved overloaded function type>)'
  vec3fClass->add(fun(&Math::operator+<float, 3>), "+");
                                              ^

Is there a way to specify each specific permutation of operator+ that exists for Vector<float, 3> (aka Vector3f)?

##2. Specific issue with operator< and operator<=

This has less to do with ChaiScript library itself and more to do with the function binding process. Both operator< and operator<= are not overloaded functions. The real problem with them is a simple but ultimately frustrating one. When I try to do something like this:

vec3fClass->add(fun(&Math::operator<<float, 3>), ">=");
vec3fClass->add(fun(&Math::operator<=<float, 3>), ">=");

the compiler mistakes operator<< as an actual operator and dumps the following compilation error:

error: 'operator<<' is not a member of 'Math'
  vec3fClass->add(fun(&Math::operator<<float, 3>), "<");
                       ^

Shame that < operator and the beginning of a template argument share the same character. Is there a way to work around this?

Sorry for the large wall of text. Thanks in advance for the help.


#2

After fiddling around a bit, I’ve been able to solve issue number 2 by simply adding a space in between operator< itself and the beginning of the template argument list.

The first issue, still stands, however.


#3

The general solution to this issue of overloaded functions is to use static cast. For example (untested)

chai.add(fun(static_cast<Vector<float, 3> (*)(const Vector<float, 3> &)>(Math::operator+<float, 3>), "+");

This is a general issue with trying to get the pointer to an overloaded C++ function that’s been answered a few times on stackoverflow.

However, that gets kind of messy, and I’ve started to lean towards C++11 lambdas instead (again untested)

chai.add(fun<Vector<float, 3> (const Vector<float, 3> &)>([](const Vector<float, 3> &v) { return +v; }, "+");

makes it a bit more obvious what you are trying to do, IMO.

Jason


Cannot register overloaded member function
#4

Changed the first one to:

chai.add(fun(static_cast<Math::Vector3f (*)(const Math::Vector3f &)>(Math::operator+<float, 3>)), "+");

It works, thanks. At least it’s a one-liner, compared to the workaround I came up with.

typedef Math::Vector3f (*promote)(const Math::Vector3f&);
chai.add(fun(promote(&Math::operator+ <float, 3>)), "+");

Debating on whether I should go down the lambdas path…