Development blog of the Molecule Engine

Main menu

Post navigation

A lesser known C++ operator

Dealing with function template code can sometimes result in errors being emitted by the compiler because template argument deduction is ambiguous. Most of the time, casts are used to battle these errors, but often there’s a more elegant solution to the problem.

The following code shows a very simple function template for returning the maximum of any two values, build as a template in order for it to work on any type:

As can be seen, even though 100 and VALUE_10 can easily be treated as ints, the template argument deduction process is ambiguous, because the types the compiler sees are int and Test, hence it doesn’t know which one to choose. The same happens with instances of type TestClass, which defines a conversion operator to int – in both cases we need to add an explicit cast as a workaround.

It would be nice if we could somehow tell the C++ compiler to carry out conversion and type promotion first, before deducing template arguments.

One thought on “A lesser known C++ operator”

Sadly, this approach doesn’t work with long longs, unsigned long longs, floats, doubles, or long doubles. Unary plus on any of these types yields a value with the same type, i.e. no promotion took place. If Max() is called on an int (or shorter) and a long long (or unsigned long long or float or double or long double), the unary plus trick isn’t enough to tell the compiler that we want the int to be promoted to match the type of the wider argument.

Perhaps what’s needed is a function-like operator that takes one or more types or expressions as arguments (similar to how sizeof can take a type or expression as an argument) and “returns” a type (similar to how a typedef’ed symbol “evaluates” to a type) which would be the result of cross-promoting types across the arguments. To avoid making yet another keyword, let’s just call it typename.

Note that the comma between typename’s parentheses is not the comma operator, it’s a separator. Otherwise the type of the expression would just be T2. Want the comma operator, for whatever reason? Use another pair of parentheses.

C++ insists on requiring the function’s return type to be named before the function is implemented. If C++ didn’t do this, maybe it could figure it out from the actual return. Turns out that this is actually possible, by using macros instead of functions! To get it right and avoid the repeated side effect problem (Max(i++, j++)), GCC typeof and statement expressions are required. Here’s the example from http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Typeof.html :