Проблема с инициализацией объекта из списка инициализаторов
У меня есть следующий код:
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});