#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;
}
Run Code Online (Sandbox Code Playgroud)
它的工作原理(实时预览)正常,但是当我尝试使用std::make_shared与std::initializer_list作为参数,我得到了错误:
auto example = new Derived({
{ 0, std::make_shared<Derived>({
{ 0, std::make_shared<Derived>() }
}) }
});
Run Code Online (Sandbox Code Playgroud)
正如您在实时预览中看到的那样.
错误:功能参数太多......
它仅适用于我这样做(实时预览):
auto example = new Derived({
{ 0, std::make_shared<Derived>(std::initializer_list<std::pair<int, std::shared_ptr<Base>>> {
{ 0, std::make_shared<Derived>() }
}) }
});
Run Code Online (Sandbox Code Playgroud)
我想知道的是:为什么它只在我传递std::initializer_listas参数std::make_shared而不是{{}}像这样使用时才起作用:
auto example = new Derived({ { 0, std::make_shared<Base>() } });
Run Code Online (Sandbox Code Playgroud)
有可能std::make_shared接受它吗?
提前致谢.
Bri*_*ian 17
之所以
auto example = new Derived({
{ 0, std::make_shared<Derived>() }
});
Run Code Online (Sandbox Code Playgroud)
工作是编译器知道它必须匹配初始化器
{{ 0, std::make_shared<Derived>() }}
Run Code Online (Sandbox Code Playgroud)
以某种方式与构造函数
Derived::Derived(std::initializer_list<std::pair<int, std::shared_ptr<Base>>>) {}
Run Code Online (Sandbox Code Playgroud)
所以很明显初始化列表的元素,
{ 0, std::make_shared<Derived>() }
Run Code Online (Sandbox Code Playgroud)
需要用来初始化a std::pair<int, std::shared_ptr<Base>>.然后它找到一对带有两个元素的构造函数,
pair::pair (const first_type& a, const second_type& b);
Run Code Online (Sandbox Code Playgroud)
这里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>() }
})
Run Code Online (Sandbox Code Playgroud)
问题是,这make_shared<Derived>是一个部分专用的函数模板,可以接受任意数字和类型的参数.因此,编译器不知道如何处理初始化列表
{{ 0, std::make_shared<Derived>() }}
Run Code Online (Sandbox Code Playgroud)
它在重载解析时不知道它需要转换为std::initializer_list<std::pair<int, std::shared_ptr<Base>>>.另外,braced-init-list永远不会std::initializer_list<T>被模板推导推断出来,所以即使你有类似的东西
std::make_shared<Derived>({0, 0})
Run Code Online (Sandbox Code Playgroud)
并且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) );
}
Run Code Online (Sandbox Code Playgroud)
或类似的东西.
另外,"剧组的" {...}到initializer_list<blah>直接(不是演员,而是一个结构)可能工作.
从理论上讲,足够的反射元编程支持可以shared_ptr在没有特征类的情况下实现这一点,这一点在管道上相当远.
| 归档时间: |
|
| 查看次数: |
4449 次 |
| 最近记录: |