Как правило, списки инициализации в фигурных скобках, такие как {}
, не являются выражениями и не имеют типа. Если у вас есть шаблон функции
template<typename T> void f(T);
и вызовите f( {} )
, для T
тип не будет выведен, и вывод типа завершится ошибкой.
С другой стороны, ABC{}
является выражением prvalue типа ABC
("явное преобразование типа в функциональной нотации"). Для такого вызова, как f( ABC{} )
, шаблон функции может вывести тип ABC
из этого выражения.
В C++14, как и в C++11, std::pair
имеет следующие конструкторы [pairs.pair]; T1
и T2
— это имена параметра шаблона шаблона класса std::pair
:
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...>);
Обратите внимание, что есть конструктор
constexpr pair(const T1& x, const T2& y); // (C)
Но нет
constexpr pair(T1&& x, T2&& y);
вместо этого есть совершенно переадресация
template<class U, class V> constexpr pair(U&& x, V&& y); // (P)
Если вы попытаетесь инициализировать std::pair
двумя инициализаторами, где хотя бы один из них является списком инициализации в фигурных скобках, конструктор (P) нежизнеспособен, так как он не может вывести аргументы своего шаблона.
(C) не является шаблоном конструктора. Типы его параметров T1 const&
и T2 const&
фиксируются параметрами шаблона класса. Ссылка на константный тип может быть инициализирована из пустого списка скобок-инициализации. Это создает временный объект, привязанный к ссылке. Поскольку указанный тип является const, конструктор (C) скопирует свои аргументы в элементы данных класса.
Когда вы инициализируете пару через std::pair<T,U>{ T{}, U{} }
, T{}
и U{}
являются prvalue-выражениями. Шаблон конструктора (P) может вывести их типы и является жизнеспособным. Создание экземпляра, созданное после вывода типа, лучше подходит, чем конструктор (C), потому что (P) создаст параметры ссылки на rvalue и привяжет к ним аргументы prvalue. (C), с другой стороны, связывает аргументы prvalue со ссылками на lvalue.
Почему тогда живой пример перемещает второй аргумент при вызове через std::pair<T,U>{ {}, U{} }
?
libstdc++ определяет дополнительные конструкторы. Ниже приведена выдержка из его реализации std::pair
из 78536ab78e, без определений функций, некоторых комментариев и SFINAE. _T1
и _T2
— имена параметров шаблона шаблона класса std::pair
.
_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...>);
Обратите внимание на шаблон конструктора (E): он скопирует первый аргумент и точно перенаправит второй. Для инициализации, такой как std::pair<T,U>{ {}, U{} }
, это жизнеспособно, потому что нужно только вывести тип из второго аргумента. Это также лучшее совпадение, чем (C) для второго аргумента, и, следовательно, лучшее совпадение в целом.
Комментарий "DR 811" есть в исходниках libstdc++. Он ссылается на LWG DR 811, который добавляет некоторые SFINAE, но не новые конструкторы.
Конструкторы (E) и (X) являются расширением libstdc++. Однако я не уверен, что это соответствует требованиям.
libc++, с другой стороны, не имеет этих дополнительных конструкторов. Для примера std::pair<T,U>{ {}, U{} }
будет скопирован второй аргумент.
Живая демонстрация с обеими реализациями библиотеки
person
dyp
schedule
05.05.2015