Issues with adding templated and/or overloaded operators


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.


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.


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.


Cannot register overloaded member function

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…