Проблема с инициализацией объекта из списка инициализаторов

У меня есть следующий код:

    class A {
        public: 
        A(std::vector<std::shared_ptr<int>>){}
    };

    auto x = std::make_shared<int>(0);
    auto y = std::make_shared<int>(1);

    auto list = {x, y};
    auto res = std::make_shared<A>({x, y});

В примере, если я перехожу к списку переменных res, он компилируется, в противном случае, как и в случае использования списка инициализаторов напрямую, происходит сбой http://ideone.com/8jYsDY

Я предполагаю, что это связано с тем, как работает вывод типов, когда задействован initializer_list. Если это стандартное соответствие, некоторые ссылки будут хорошими.

1 ответ

Решение

std::make_shared выводит свой второй параметр шаблона из аргументов вызова функции. Braced-init-list не является выражением и поэтому не имеет типа. Следовательно, вывод аргумента шаблона не может вывести тип из него.

Из §14.8.2.5/5 [temp.deduct.type]

Неведуемые контексты:
- ...
- параметр функции, для которого связанный аргумент является списком инициализатора (8.5.4), но параметр не имеет std::initializer_list или ссылка на возможно cv-квалифицированное std::initializer_list тип. [ Пример:

 template<class T> void g(T);
 g({1,2,3}); // error: no argument deduced for T

- конец примера ]

auto Однако это особый случай, который позволяет вывести std::initializer_list<T> из списка инициалов.

§7.1.6.4 / 7 [dcl.spec.auto]

... В противном случае, получить P от T заменив вхождения auto либо с новым параметром шаблона изобретенного типа U, либо, если инициализатором является список фигурных скобок, с std::initializer_list<U> , Выведите значение для U используя правила вывода аргументов шаблона из вызова функции (14.8.2.1), где P тип параметра шаблона функции, а инициализатор - соответствующий аргумент. Если вычет не удался, декларация неверна. В противном случае тип, выведенный для переменной или возвращаемого типа, получается путем подстановки выведенного U в P, [ Пример:

 auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
 auto x2 = { 1, 2.0 }; // error: cannot deduce element type

- конец примера ]

В вашем примере переменная list имеет тип initializer_list<shared_ptr<int>> и когда вы передаете его make_shared, vector может быть построен из него, который затем используется для прямой инициализации A пример.

Другие варианты - построить vector

auto res = std::make_shared<A>(std::vector<std::shared_ptr<int>>{x, y});

построить A, который затем будет перемещен

auto res = std::make_shared<A>(A{{x, y}});

или укажите параметры шаблона для make_shared эксплицитно

auto res = std::make_shared<A, std::initializer_list<std::shared_ptr<int>>>({x, y});
Другие вопросы по тегам