I'm completely confused after reading the question How to make these std::function parameters unambiguous?, so far I'd thought I understood what partial ordering of function templates is, but after reading that question I wrote down three examples to check the compiler's behavior, and the results received are hard for me to understand.
Example #1
template <class T>
void foo(T) {}
template <class T>
void foo(T&) {}
int main()
{
int i;
foo<int>(i); // error: call is ambiguous!
}
Question: Both functions are viable, that's obvious, but isn't the one taking T&
more specialized than T
? Instead, the compiler raises ambiguous call error.
Example #2
#include <iostream>
template <class T>
struct X {};
template <>
struct X<int>
{
X() {}
X(X<int&> const&) {} // X<int> is constructible from X<int&>
// note: this is not a copy constructor!
};
template <>
struct X<int&>
{
X() {}
X(X<int> const&) {} // X<int&> is constructible from X<int>
// note: this is not a copy constructor!
};
template <class T>
void bar(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void bar(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
bar<int>(X<int>()); // calls void bar(X<T>) [with T = int]
bar<int>(X<int&>()); // calls void bar(X<T&>) [with T = int]
}
Question: If the T&
and T
are ambiguous in Example #1, then why here none call is ambiguous? X<int>
is constructible from X<int&>
, as well as X<int&>
is constructible from X<int>
thanks to provided constructors. Is it because compiler generated X<int>::X(X<int> const&)
copy-constructor is a better conversion sequence than X<int>::X(X<int&> const&)
, (if so, what makes it better, note that arguments are passed by value), and so the ordering of specializations does not matter at all?
Example #3
#include <iostream>
// note: a new type used in constructors!
template <class U>
struct F {};
template <class T>
struct X
{
X() {}
template <class U>
X(F<U> const&) {} // X<T> is constructible from any F<U>
// note: it takes F type, not X!
};
template <class T>
void qux(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void qux(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
qux<int>(F<int>()); // calls void qux(X<T&>) [with T = int]
qux<int>(F<int&>()); // calls void qux(X<T&>) [with T = int]
}
Question: Now this is similar scenario to "matching lambda [](int){}
against std::function<void(int&)>
and std::function<void(int)>
" from question linked. Why in both calls the more specialized function template is picked? Is it because the conversion sequence is the same, so partial ordering starts to matter?
All tests done on GCC 4.9.0 with -std=c++11
and no extra flags.