集合中的智能指针多态性

Smart pointer polymorphism in collections

我正在尝试通过初始化列表初始化指向 class A 的指针集合。但是,初始化列表不能使用引用作为模板类型。

我有以下代码。

#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <memory>

struct A
{
    virtual void f() const noexcept { std::cout << "A"; }
};

struct B : public A
{
    virtual void f() const noexcept override { std::cout << "B"; }
};

class Test
{
    std::vector<std::shared_ptr<A>> vec;
public:
    Test(const std::initializer_list<A>& list)
    //Test(const std::initializer_list<A&>& list) <------ Solution?
    {
        for (auto& x : list)
            vec.push_back(std::make_shared<A>(x));
    }
    void print()
    {
        std::for_each(vec.begin(), vec.end(), [](auto x) { x->f(); });
    }
};

int main()
{
    Test test = { A(), B() };
    test.print();
}

代码打印:

AA

它应该打印:

AB

有没有一种简单的方法可以做到这一点,而不必在调用方法中创建指针?

相关文章(How do I implement polymorphism with std::shared_ptr?)对这个问题没有提供太多帮助。

您将在下一行shared_ptr创建新的

        vec.push_back(std::make_shared<A>(x));

x 是什么并不重要,您用它的值创建了一个新的 A

您可能想要创建一个 shared_ptr<A> 并将指针从 x.get() 传递到新的空 shared_ptr<A>

std::initializer_list<T>按值保存传递的对象,所以不能存在多态。另外 std::make_shared<A> 总是创建一个 A 类型的对象,而不是从 A 派生的某种类型。你需要另一种方法。

由于您有任意数量的任意类型的参数,您可能需要一个可变参数模板构造函数。

编辑:我的代码建议太复杂了。 WhozCraig 的评论好多了:

template<class... Args>
Test(Args&&... args) :
    vec { std::make_shared<std::remove_reference_t<Args>>(std::forward<Args>(args))... }
{
}

您正在使用 std::make_shared<A>() 插入向量。您正在将一堆 BA 复制到一堆 A.

如果您希望 main 中的语法起作用,最简单的方法是使用模板:

struct Foo {
    template<typename... Args>
    Foo(Args... args) :
        vec{std::make_shared<Args>(std::move(args))...}
    {}

private:
    std::vector<std::shared_ptr<A>> vec;
};