cpgf library documentation

Use C++ operator wrapper functions from script

The tool Metagen can generate named functions as wrapper for C++ operators. That allows most overloaded C++ operators can be used from script language, such as Javascript, which doesn't support operator overloading. The operator wrapper is portable. It behaves exactly same in all supported script languages – Lua, JavaScript, and Python.

Though cpgf Lua binding already supports C++ operators, and in the future Python binding may support it too, usually the script languages support much less kinds of operators than C++, and operator overloading can't be ported between different script languages (imagine if we need to port Lua code to JavaScript).

Use the operator wrapper

In C++ the operator overloading makes “a + b” looks very sweet, but in fact it's a kind of syntax sugar to the raw form “a.operator + (b)”, in which the operator is used in function syntax.

Metagen generates wrapper similar as the function syntax, and map each C++ operator to a function. So in script, when we want to add two objects, we call a._opAdd(b). It's awkward than “a + b”, but not worse than “a.operator + (b)”.

Note: metagen only generates wrapper for class member operators, global operators are not wrapped.

The table below shows how C++ operators are mapped to function.

C++ operator Function name C++ code Script code
Addition + _opAdd 1 a + b a._opAdd(b)
Subtraction - _opSub a - b a._opSub(b)
Multiplication * _opMul a * b a._opMul(b)
Division / _opDiv a / b a._opDiv(b)
Modulo % _opMod a % b a._opMod(b)
Unary plus + _opPlus +a a._opPlus()
Unary minus - _opMinus -a a._opMinus()
Addition assignment += _opAddAssign a += b a._opAddAssign(b)
Subtraction assignment -= _opSubAssign a -= b a._opSubAssign(b)
Multiplication assignment *= _opMulAssign a *= b a._opMulAssign(b)
Division assignment /= _opDivAssign a /= b a._opDivAssign(b)
Modulo assignment %= _opModAssign a %= b a._opModAssign(b)
Basic assignment = _opAssign a = b a._opAssign(b)
Equal to == _opEqual a == b a._opEqual(b)
Not equal to != _opNotEqual a != b a._opNotEqual(b)
Greater than > _opGreater a > b a._opGreater(b)
Less than < _opLess a < b a._opLess(b)
Greater than or equal to >= _opGreaterEqual a >= b a._opGreaterEqual(b)
Less than or equal to <= _opLessEqual a <= b a._opLessEqual(b)
Logical AND && _opAnd a && b a._opAnd(b)
Logical OR || _opOr a || b a._opOr(b)
Logical negation (NOT) ! _opNot !a a._opNot()
Bitwise AND & _opBitAnd a & b a._opBitAnd(b)
Bitwise OR | _opBitOr a | b a._opBitOr(b)
Bitwise XOR ^ _opBitXor a ^ b a._opBitXor(b)
Bitwise left shift << _opLeftShift a << b a._opLeftShift(b)
Bitwise right shift >> _opRightShift a >> b a._opRightShift(b)
Bitwise NOT ~ _opBitNot ~a a._opBitNot()
Bitwise AND assignment &= _opBitAndAssign a &= b a._opBitAndAssign(b)
Bitwise OR assignment |= _opBitOrAssign a |= b a._opBitOrAssign(b)
Bitwise XOR assignment ^= _opBitXorAssign a ^= b a._opBitXorAssign(b)
Bitwise left shift assignment <<= _opLeftShiftAssign a <<= b a._opLeftShiftAssign(b)
Bitwise right shift assignment >>= _opRightShiftAssign a >>= b a._opRightShiftAssign(b)
Prefix increment ++ _opInc ++a a._opInc()
Prefix decrement -- _opDec --a a._opDec()
Suffix increment ++ _opIncSuffix a++ a._opIncSuffix()
Suffix decrement -- _opDecSuffix a-- a._opDecSuffix()
Comma , _opComma a , b a._opComma(b)
Array item get [] 2 _opArrayGet v = a[index] v = a._opArrayGet(index)
Array item set [] 2 _opArraySet a[index] = v a._opArraySet(index, v)
Function call () _opFunction a(a1, a2, a3) a._opFunction(a1, a2, a3)
Reference & _opAddress &a a._opAddress(b)
Indirection * _opDerefer *a a._opDerefer(b)

1 Why do we use so ugly name like _opAdd() instead of just add()? This is deliberate to avoid name conflicting. Those functions' meta data are reflected into any classes, in which there may be already some member functions such as add, plus, div, etc.

2 Array subscript operator is wrapped in two functions, getter and setter. Metagen generates the setter function when and only when the operator result value is a reference to non-const, for example, “int & operator[] (int index)”

Unwrapped operators

The operators that are not wrapped is “→”, “→*”, and type casting. They are very hard to wrap, and it makes no sense to wrap them. The operators new and delete are not wrapped too, but we don't need them. We can always create new instance and ignore the overloaded new and delete operators.

Code samples

Assume we have a class vector, which supports +-*/ operators and the normalize function. Then if have C++ code

// This is a modification code in Irrlicht sample code 07.Collision.
// It calculates a ray cast from the camera.
vector start = camera->getPositionVector();
vector end = start + (camera->getTargetVector() - start).normalize() * 1000.0;

Then in JavaScript we can write

// This is a modification code in Irrlicht sample code 07.Collision
// It calculates a ray cast from the camera.
var start = camera.getPositionVector();
var end = start._opAdd(camera.getTargetVector()._opSub(start).normalize()._opMul(1000.0));