In general, bit-init lists, such as {} , are not expressions and are not of type. If you have a function template
template<typename T> void f(T);
and call f( {} ) , the type will not be inferred for T , and the type inference will not be executed.
On the other hand, ABC{} is a prvalue expression of type ABC ("explicit type conversion in functional notation"). For a call of type f( ABC{} ) the function template can deduce the type ABC from this expression.
In C ++ 14, as well as in C ++ 11, std::pair has the following [pairs.pair] constructors; T1 and T2 are std::pair class template template parameter names:
pair(const pair&) = default; pair(pair&&) = default; constexpr pair(); constexpr pair(const T1& x, const T2& y); template<class U, class V> constexpr pair(U&& x, V&& y); template<class U, class V> constexpr pair(const pair<U, V>& p); template<class U, class V> constexpr pair(pair<U, V>&& p); template <class... Args1, class... Args2> pair(piecewise_construct_t, tuple<Args1...>, tuple<Args2...>);
Note that there is a constructor
constexpr pair(const T1& x, const T2& y);
But not
constexpr pair(T1&& x, T2&& y);
instead there is excellent shipping
template<class U, class V> constexpr pair(U&& x, V&& y);
If you try to initialize std::pair with two initializers, in which at least one of them is a list of bit-init, constructor (P) is not viable because it cannot print its template arguments.
(C) is not a constructor template. Its parameters parameters T1 const& and T2 const& are fixed by the parameters of the class template. A reference to a constant type can be initialized from an empty list with binding to init-init. This creates a temporary object bound to the link. Since a type called const, the constructor (C) copies its arguments to the data members of the class.
When you initialize a pair via std::pair<T,U>{ T{}, U{} } , T{} and U{} are prvalue expressions. The constructor template (P) can infer their types and is viable. Creating an instance created after type inference is a better match than the (C) constructor, because (P) will give rvalue-reference parameters and bind the prvalue arguments to them. (C), on the other hand, binds prvalue arguments to lvalue references.
Why then does a live example move the second argument when called through std::pair<T,U>{ {}, U{} } ?
libstdc ++ defines additional constructors. The following is an excerpt from its std::pair implementation from 78536ab78e, omitting function definitions, some comments, and SFINAE. _T1 and _T2 are the parameter names of the template template for the std::pair class.
_GLIBCXX_CONSTEXPR pair(); _GLIBCXX_CONSTEXPR pair(const _T1& __a, const _T2& __b); // (C) template<class _U1, class _U2> constexpr pair(const pair<_U1, _U2>& __p); constexpr pair(const pair&) = default; constexpr pair(pair&&) = default; // DR 811. template<class _U1> constexpr pair(_U1&& __x, const _T2& __y); // (X) template<class _U2> constexpr pair(const _T1& __x, _U2&& __y); // (E) <===================== template<class _U1, class _U2> constexpr pair(_U1&& __x, _U2&& __y); // (P) template<class _U1, class _U2> constexpr pair(pair<_U1, _U2>&& __p); template<typename... _Args1, typename... _Args2> pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>);
Note the constructor template (E): it will copy the first argument and redirect the second one perfectly. For initialization, such as std::pair<T,U>{ {}, U{} } , it is viable because it only needs to infer the type from the second argument. This is also a better match than (C) for the second argument, and therefore a better match overall.
The comment "DR 811" is contained in libstdc ++ sources. It refers to the LWG DR 811 , which adds some SFINAE but does not contain new constructors.
Constructors (E) and (X) are extensions to libstdc ++. I'm not sure if this is compatible.
libC ++, on the other hand, has no additional constructors. For example, std::pair<T,U>{ {}, U{} } it will copy the second argument .
Live demo with both library implementations