std::make_shared with std::initializer_list

后端 未结 2 2004
死守一世寂寞
死守一世寂寞 2020-12-03 14:14
#include 
#include 

class Base
{
public:
    Base() {}
};

class Derived : public Base
{
public:
    Derived() {}
    Derived(std::ini         


        
2条回答
  •  甜味超标
    2020-12-03 14:27

    The reason why

    auto example = new Derived({
        { 0, std::make_shared() }
    });
    

    works is that the compiler knows that it has to match the initializer

    {{ 0, std::make_shared() }}
    

    somehow with the constructor

    Derived::Derived(std::initializer_list>>) {}
    

    So it is clear that the element of the initializer list,

    { 0, std::make_shared() }
    

    needs to be used to initialize a std::pair>. It then finds a constructor for the pair that takes two elements,

    pair::pair (const first_type& a, const second_type& b);
    

    where first_type is int and second_type is std::shared_ptr. So finally we see that the argument std::make_shared() is implicitly converted to std::shared_ptr, and we're good to go!

    In the above, I pointed out that the compiler handles initializer lists by looking for a constructor that accepts either an initializer list directly, or the appropriate number of arguments, to which the initializer list's elements are then passed, after appropriate implicit conversions if necessary. For example, the compiler can figure out that your std::shared_ptr needs to be implicitly converted to std::shared_ptr in the above example only because the pair's constructor demands it.

    Now consider

    std::make_shared({
            { 0, std::make_shared() }
        })
    

    The problem is that make_shared is a partially specialized function template that can accept arguments of arbitrary number and type. Because of this, the compiler has no idea how to handle the initializer list

    {{ 0, std::make_shared() }}
    

    It doesn't know at the time of overload resolution that it needs to be converted to std::initializer_list>>. Additionally, a braced-init-list is never deduced as std::initializer_list by template deduction, so even if you had something like

    std::make_shared({0, 0})
    

    and Derived had an appropriate constructor taking std::initializer_list, it still wouldn't work, for the same reason: std::make_shared would not be able to deduce any type for its argument.

    How to fix this? Unfortunately, I cannot see any easy way. But at least now you should know why what you wrote doesn't work.

提交回复
热议问题