[英]How to call std::make_shared in case of initializer_list arguments?
[英]std::make_shared with std::initializer_list
#include <iostream>
#include <memory>
class Base
{
public:
Base() {}
};
class Derived : public Base
{
public:
Derived() {}
Derived(std::initializer_list<std::pair<int, std::shared_ptr<Base>>>) {}
};
int main(int argc, char ** argv)
{
auto example = new Derived({
{ 0, std::make_shared<Derived>() }
});
return 0;
}
它正常工作( 实时预览 ),但是当我尝试将std::make_shared
与std::initializer_list
用作参数时,出现错误:
auto example = new Derived({
{ 0, std::make_shared<Derived>({
{ 0, std::make_shared<Derived>() }
}) }
});
如您在此处看到的实时预览 。
错误:功能太多参数...
它仅在执行此操作( 实时预览 )时有效:
auto example = new Derived({
{ 0, std::make_shared<Derived>(std::initializer_list<std::pair<int, std::shared_ptr<Base>>> {
{ 0, std::make_shared<Derived>() }
}) }
});
我想知道的是:为什么仅当我将std::initializer_list
作为参数传递给std::make_shared
而不是像这样使用{{}}
时,它才起作用:
auto example = new Derived({ { 0, std::make_shared<Base>() } });
有可能使std::make_shared
接受它吗?
提前致谢。
之所以
auto example = new Derived({
{ 0, std::make_shared<Derived>() }
});
起作用的是编译器知道它必须匹配初始化程序
{{ 0, std::make_shared<Derived>() }}
以某种方式与构造函数
Derived::Derived(std::initializer_list<std::pair<int, std::shared_ptr<Base>>>) {}
因此很明显,初始化器列表的元素,
{ 0, std::make_shared<Derived>() }
需要用于初始化std::pair<int, std::shared_ptr<Base>>
。 然后,为包含两个元素的一对查找构造函数,
pair::pair (const first_type& a, const second_type& b);
其中first_type
是int
, second_type
是std::shared_ptr<Base>
。 所以最后我们看到参数std::make_shared<Derived>()
被隐式转换为std::shared_ptr<Base>
,我们很高兴!
在上面,我指出了编译器通过寻找一个构造器来处理初始化器列表,该构造器直接接受初始化器列表或适当数量的参数,然后在必要时进行适当的隐式转换,然后将初始化器列表的元素传递给该参数。 例如,在上面的示例中,编译器可以发现需要将std::shared_ptr<Derived>
隐式转换为std::shared_ptr<Base>
,这是因为该对的构造函数需要这样做。
现在考虑
std::make_shared<Derived>({
{ 0, std::make_shared<Derived>() }
})
问题在于make_shared<Derived>
是部分专用的函数模板,可以接受任意数量和类型的参数。 因此,编译器不知道如何处理初始化程序列表
{{ 0, std::make_shared<Derived>() }}
在重载解决方案时尚不知道需要将其转换为std::initializer_list<std::pair<int, std::shared_ptr<Base>>>
。 此外,通过模板推导,不会将支撑初始列表推导出为std::initializer_list<T>
,因此即使您有类似
std::make_shared<Derived>({0, 0})
和Derived
具有采用std::initializer_list<int>
的适当构造函数,出于相同的原因,它仍然不起作用: std::make_shared<Derived>
不能为其参数推断任何类型。
如何解决这个问题? 不幸的是,我看不到任何简单的方法。 但是至少现在您应该知道为什么您写的内容行不通。
为此,您需要创建一个自定义make_shared_from_list
,因为make_shared
不支持非显式的初始化列表。 原因由@brian很好地描述了。
我将使用traits类将类型T
映射到初始化列表的类型。
template<class>struct list_init{};// sfinae support
template<> struct list_init<Derived>{using type=std::pair<int, std::shared_ptr<Base>>;};
template<class T>using list_init_t=typename list_init<T>::type;
template<class T>
std::shared_ptr<T> make_shared_from_list( std::initializer_list<list_init_t<T>> list ){
return std::make_shared<T>( std::move(list) );
}
或类似的东西。
另外,也可以将{...}
直接“投射”到initializer_list<blah>
(不是强制转换,而是构造)。
从理论上讲,足够的反射元编程支持将允许shared_ptr
在没有traits类的情况下执行此操作,该类非常遥远。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.