Function Overloading Based on Value vs. Const Reference

kirakun picture kirakun · Mar 28, 2011 · Viewed 9.4k times · Source

Does declaring something like the following

void foo(int x)        { std::cout << "foo(int)"         << std::endl; }
void foo(const int &x) { std::cout << "foo(const int &)" << std::endl; }

ever make sense? How would the caller be able to differentiate between them? I've tried

foo(9);  // Compiler complains ambiguous call.

int x = 9;
foo(x);  // Also ambiguous.

const int &y = x;
foo(y);  // Also ambiguous.

Answer

Alexander Gessler picture Alexander Gessler · Mar 28, 2011

The intent seems to be to differenciate between invocations with temporaries (i.e. 9) and 'regular' argument passing. The first case may allow the function implementation to employ optimizations since it is clear that the arguments will be disposed afterwards (which is absolutely senseless for integer literals, but may make sense for user-defined objects).

However, the current C++ language standard does not offer a way to overload specifically for the 'l/r-valueness' of arguments - any l-value being passed as argument to a function can be implicitly converted to a reference, so the ambiguity is unavoidable.

C++11 introduces a new tool for a similar purpose — using r-value references, you can overload as follows

void foo(int x)        { ... }
void foo(const int &&x) { ... }

... and foo(4) (a temporary, r-value passed as argument) would cause the compiler to pick the second overload while int i = 2; foo(i) would pick the first.

(note: even with the new toolchain, it is not possible to differentiate between the cases 2 and 3 in your sample!)