Reputation: 4505
I have the following code:
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});
In the example if I pass to res variable list it compiles, otherwise as in the case of using initializer list directly it fails http://ideone.com/8jYsDY
I guess it has to do with the way type deduction works when initializer_list are involved. If this is standard conformant some reference would be good.
Upvotes: 1
Views: 184
Reputation: 109089
std::make_shared
deduces its second template parameter from the arguments to the function call. A braced-init-list is not an expression, and as such, has no type. Hence template argument deduction cannot deduce a type from it.
From §14.8.2.5/5 [temp.deduct.type]
The non-deduced contexts are:
—...
— A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter does not havestd::initializer_list
or reference to possibly cv-qualifiedstd::initializer_list
type. [ Example:template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
—end example ]
auto
, however, is a special case that is allowed to deduce std::initializer_list<T>
from a braced-init-list.
§7.1.6.4/7 [dcl.spec.auto]
...
Otherwise, obtainP
fromT
by replacing the occurrences ofauto
with either a new invented type template parameter U or, if the initializer is a braced-init-list, withstd::initializer_list<U>
. Deduce a value forU
using the rules of template argument deduction from a function call (14.8.2.1), whereP
is a function template parameter type and the initializer is the corresponding argument. If the deduction fails, the declaration is ill-formed. Otherwise, the type deduced for the variable or return type is obtained by substituting the deducedU
intoP
. [ Example:auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> auto x2 = { 1, 2.0 }; // error: cannot deduce element type
—end example ]
In your example, the variable list
has the type initializer_list<shared_ptr<int>>
, and when you pass it to make_shared
, a vector
can be constructed from it, which is then used to direct-initialize the A
instance.
Other options are to construct a vector
auto res = std::make_shared<A>(std::vector<std::shared_ptr<int>>{x, y});
construct an A
, which will then be moved
auto res = std::make_shared<A>(A{{x, y}});
or specify the template parameters for make_shared
explicitly
auto res = std::make_shared<A, std::initializer_list<std::shared_ptr<int>>>({x, y});
Upvotes: 1