1

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.

1 Answer 1

1

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 have std::initializer_list or reference to possibly cv-qualified std::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, obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list, with std::initializer_list<U>. Deduce a value for U using the rules of template argument deduction from a function call (14.8.2.1), where P 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 deduced U into P. [ 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});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.