I ran into a real-life WTF moment when I discovered that the code below outputs "pointer".
#include <iostream>
#include <utility>
template<typename T>
struct bla
{
static void f(const T*) { std::cout << "pointer\n"; }
static void f(const T&) { std::cout << "reference\n"; }
};
int main()
{
bla<std::pair<int,int>>::f({});
}
Changing the std::pair<int,int>
template argument to an int
or any other primitive type, gives the (for me at least) expected "ambiguous overload" error. It seems that builtin types are special here, because any user-defined type (aggregate, non-trivial, with defaulted constructor, etc...) all lead to the pointer overload being called. I believe the template is not necessary to reproduce it, it just makes it simple to try out different types.
Personally, I don't think that is logical and I would expect the ambiguous overload error in all cases, regardless of the template argument. GCC and Clang (and I believe MSVC) all disagree with me, across C++11/14/1z. Note I am fully aware of the bad API these two overloads present, and I would never write something like this, I promise.
So the question becomes: what is going on?