Question

For the following code:

class A {};

template <typename T> void f(T& a) {}
template <typename T> void f(T&& a) {}

int main() {
    A a;
    f(a);
}

clang++ binds the call to the first overload, while g++ reports ambiguous call. Which one is taking the correct action?

Was it helpful?

Solution

Both gcc 4.9.0 20140302 and clang 3.5 (trunk 202594) correctly pick the first version. As hvd kindly gave me the references in comments:

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):
— if the type from the argument template was an lvalue reference and the type from the parameter template was not, the argument type is considered to be more specialized than the other; otherwise,
— if the type from the argument template is more cv-qualified than the type from the parameter template (as described above), the argument type is considered to be more specialized than the other; otherwise,
— neither type is more specialized than the other.


By the way, watch The Universal Reference/Overloading Collision Conundrum video why overloading on universal references is a bad idea. In short, consider the following example:

#include <iostream>
#include <utility>

struct A { bool guts_stolen; };

void steal_guts(A&& a) {
  a.guts_stolen = true; 
}

template <typename T> void f(const T& a) { 
                          // ^^^^^ note the const!
  std::cout << "T&\n"; 
}

template <typename T> void f(T&& a) { 
  std::cout << "T&&\n";
  steal_guts(std::move(a));
}

int main() {
    A a{ false };
    f(a);
    std::cout << "Guts stolen? " << std::boolalpha << a.guts_stolen << std::endl;
}

If you run the program, it will print

T&&
Guts stolen? true

which is not at all what you would expect just by looking at A a{ false }; f(a);.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top