Вывод типа std::initializer_list

Недавно я написал очень простой класс.

class C
{
public:
    void AddString(std::initializer_list<std::pair<const char*,int>> x)
    {
          //irrelevant
    }
};

int main()
 {
           C c;
           c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });
           .... //other unimportant stuff
           return 0;
 }

К моему приятному удивлению, он скомпилировался и работал корректно. Может кто-нибудь объяснить мне, как компилятор смог сделать вывод, что вложенные инициализаторы в фигурных скобках были для std::pair? Я использую MSVS 2013.


person pebbleonthebeach    schedule 21.05.2015    source источник


Ответы (1)


c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });

Вы передаете braced-init-list, который сам содержит вложенные brace-init-list, в AddString. Аргумент может соответствовать параметру std::initializer_list<std::pair<const char*,int>>, если внутренний список инициализации в фигурных скобках можно преобразовать в std::pair<const char*,int>.

Этот процесс разрешения перегрузки происходит в два этапа; сначала делается попытка сопоставить конструкторы std::pair, которые принимают аргумент std::initializer_list. Поскольку std::pair не имеет такого конструктора, выполняется второй шаг, на котором перечисляются другие конструкторы std::pair<const char*,int>. с char const[2] и int в качестве аргументов. Это будет соответствовать следующему конструктору pair, поскольку char const[2] неявно преобразуется в char const *, а сам конструктор не является explicit.

template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );

Цитирование N3337 §13.3.1.7/1 [over.match.list]

Когда объекты неагрегатного типа класса T инициализируются списком (8.5.4), разрешение перегрузки выбирает конструктор в два этапа:
Первоначально функции-кандидаты являются конструкторами списка инициализаторов (8.5.4) класса class T, а список аргументов состоит из списка инициализаторов в качестве одного аргумента.
Если жизнеспособный конструктор списка инициализаторов не найден, снова выполняется разрешение перегрузки, где функциями-кандидатами являются все конструкторы класса. T, а список аргументов состоит из элементов списка инициализаторов.

Если в списке инициализаторов нет элементов, а T имеет конструктор по умолчанию, первая фаза опускается. При инициализации списка копирования, если выбран конструктор explicit, инициализация имеет неверный формат.

person Praetorian    schedule 21.05.2015
comment
Отличный ответ, гораздо более полный! - person vsoftco; 21.05.2015
comment
Спасибо, это проясняет некоторые вещи. Мне нужно немного больше понять о разрешении перегрузки, когда задействованы списки инициализации в фигурных скобках. - person pebbleonthebeach; 21.05.2015
comment
@pebbleonthebeach Правила разрешения перегрузки, когда задействована инициализация списка, - это то, что я скопировал выше. Если вы имели в виду, что вам необходимо ознакомиться с разрешением перегрузок в целом, я предлагаю вам начать с это видео (посмотрите всю серию, если найдете время). - person Praetorian; 22.05.2015