Краткий ответ
Для s2
используется синтаксис фигурной скобки, а {a.begin(), a.end()}
считается initializer_list
из std::array<int>::iterator
с. Следовательно, s2
- это набор итераторов.
Для s3
используется синтаксис скобок, и выбирается конструктор итератора. s3
является набором int
с и инициализируется из диапазона [a.begin(), a.end())
.
Длинный ответ
За [set.overview] , у нас есть два руководства по выводам, относящиеся здесь:
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
set(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
и
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
За [over.match.class.deduct] / 1 :
Формируется набор функций и шаблонов функций, содержащий:
В этом случае синтезированные функции и шаблоны функций для вышеупомянутых руководств по выводам, соответственно,
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
auto __func1(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
и
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
auto __func2(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
(Я использовал двойные подчеркивания, чтобы показать, что эти имена синтезированы и не доступны иным образом.)
За [over.match.class.deduct] / 2 :
Инициализация и разрешение перегрузки выполняются, как описано в
[dcl.init] и [over.match.ctor], [over.match.copy] или
[over.match.list] (в зависимости от типа инициализации
выполняется) для объекта гипотетического типа класса, где
выбранные функции и шаблоны функций считаются
конструкторы этого типа класса с целью формирования перегрузки
установить, и инициализатор предоставляется контекстом, в котором класс
вычет аргумента шаблона был выполнен. Каждый такой понятийный
конструктор считается явным, если функция или функция
шаблон был сгенерирован из конструктора или deduction-guide , который
был объявлен explicit
. Все такие условные конструкторы считаются
быть публичными членами гипотетического типа класса.
Гипотетический тип класса выглядит следующим образом:
class __hypothetical {
public:
// ...
// #1
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
__hypothetical(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
// #2
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
__hypothetical(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
// ...
};
Для декларации s2
,
std::set s2 {a.begin(), a.end()};
Разрешение перегрузки выполняется как в
__hypothetical __hyp{a.begin(), a.end()}; // braces
Таким образом, [over.match.list] входит.
[...] разрешение перегрузки выбирает конструктор в два этапа:
Конструктор # 2 является конструктором списка инициализаторов . Вывод аргумента шаблона функции дает
Key = std::array<int>::iterator
Таким образом, выведенный тип s2
равен
std::set<std::array<int>::iterator>
Объявление s2
эквивалентно
std::set<std::array<int>::iterator> s2 {a.begin(), a.end()};
Следовательно, s2
- это набор итераторов, состоящий из двух элементов: a.begin()
и a.end()
. В вашем случае std::array<int>::iterator
, вероятно, int*
, а a.begin()
и a.end()
сериализуются как 0x7ffecf9d12e0
и 0x7ffecf9d12f0
, соответственно.
Для s3
разрешение перегрузки выполняется как в
__hypothetical __hyp(a.begin(), a.end()); // parentheses
Это прямая инициализация и относится к области действия [pver.match.ctor] . Конструктор initializer_list
не имеет значения, и вместо него выбирается Конструктор # 1. Вывод аргумента шаблона функции дает
InputIterator = std::array<int>::iterator
Таким образом, выведенный тип s3
равен
set<iterator_traits<std::array<int>::iterator>::value_type>
Что такое set<int>
. Следовательно, объявление s3
эквивалентно
std::set<int> s3 (a.begin(), a.end());
s3
- это набор int
с, который инициализируется из диапазона [a.begin(), a.end())
& mdash; четыре элемента 1, 2, 3, 4
, что объясняет вывод.