函数模板,用于将shared_ptr的向量填充到基础对象和派生对象

sif*_*man 2 c++ inheritance templates shared-ptr stdvector

考虑以下:

#include <memory>
#include <utility>
#include <vector>

class Base
{
public:
    Base()
        : x(0)
    {}
    int x;
    virtual ~Base() = default;
};

class Derived : public Base
{
public:
    Derived(double z0)
        : Base{}
        , z{ z0 }
    {}
    double z;
};

template<class T> // T might be either a Base or a Derived class.
std::vector<std::shared_ptr<Base>> MakeVector(std::size_t numElements)
{
    std::vector<std::shared_ptr<Base>> vec;
    for(auto &i : numElements) {     // Compiler error occurs here.
        vec.push_back(std::make_shared<T>());
    }
    return vec;
}

class Foo
{
public:
    Foo(std::size_t num_elements,
        std::vector<std::shared_ptr<Base>> bars = {})
    : m_bars{bars.empty() ? MakeVector<Base>(num_elements) : std::move(bars)}
    {}

    std::vector<std::shared_ptr<Base>> m_bars;
};

int main()
{
    const std::size_t foo1Size = 4;
    const std::size_t foo2Size = 5;

    // Create a vector of shared_ptr to 4 Base objects:
    Foo foo1 {foo1Size};

    // Create a vector of shared_ptr to 5 Derived objects:
    Foo foo2 {foo2Size, MakeVector<Derived>(foo2Size)};
}
Run Code Online (Sandbox Code Playgroud)

这里的目标是创建的请求数量BaseDerived对象,并填充std::vectorshared_ptrs到这些对象。

我在以下for语句中收到编译器错误:

错误:没有'begin'参数依赖模板参数,因此'begin'声明必须可用[-fpermissive]

如果我使用std::iteratorwith beginend,不幸的是每个迭代器都无效push_back。无论如何,我都需要迭代特定的次数来填充向量。

这个问题有明显的解决方案吗?

son*_*yao 6

  1. 您不能使用范围为基础的循环std::size_t。你可以改变

    for(auto &i : numElements) {
    
    Run Code Online (Sandbox Code Playgroud)

    for (std::size_t i = 0; i < numElements; i++) { 
    
    Run Code Online (Sandbox Code Playgroud)
  2. Derived没有默认的构造函数;您需要将参数传递给它进行构造,否则std::make_shared<T>()会失败。您可以MakeVector使用参数pack更改为以下内容:

    template<class T, class... Types> // T might be either a Base or a Derived class.
    std::vector<std::shared_ptr<Base>> MakeVector(std::size_t numElements, Types... args)
    {
        std::vector<std::shared_ptr<Base>> vec;
        for (std::size_t i = 0; i < numElements; i++) {
            vec.push_back(std::make_shared<T>(args...));
        }
        return vec;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后像

    // Create a vector of shared_ptr to 5 Derived objects:
    Foo foo2 {foo2Size, MakeVector<Derived>(foo2Size, 42)};
    
    Run Code Online (Sandbox Code Playgroud)


JeJ*_*eJo 5

numElements是一个std::size_t不具有类型beginend迭代器定义,这是所需的(这是对于标准容器和用户定义的类型,而不是原始类型定义)基于范围的for循环。因此,您需要一个经典for循环

for(std::size_t index{ 0 }; index  < numElements; index ++) 
{ 
    vec.push_back(std::make_shared<T>());
}
Run Code Online (Sandbox Code Playgroud)

或者只是一个while循环:

while(numElements--)
{
    vec.push_back(std::make_shared<T>());
}
Run Code Online (Sandbox Code Playgroud)

其次,正如@songyuanyao指出的那样,Derived类必须具有default构造函数MakeVector才能起作用。您可以像这样默认一个:

Derived() = default;
// or
// Derived(double z0 = 0.0): Base{}, z{ z0 } {}
Run Code Online (Sandbox Code Playgroud)

@songyuanyao的答案中最好的类似,为构造函数参数提供额外的varidic-template-args。