Consider the following:
#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)};
}
The objective here is to create a requested number of Base
or Derived
objects, and populate a std::vector
with shared_ptr
s to those objects.
I am getting a compiler error on the for
statement:
error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available [-fpermissive]
If I use a std::iterator
with begin
and end
, unfortunately the iterator becomes invalid with each push_back
. And I need to iterate a specific number of times, anyway, to populate the vector.
Is there an obvious solution to this problem?
You can't use range-based for loop on an std::size_t
. You could change
for(auto &i : numElements) {
to
for (std::size_t i = 0; i < numElements; i++) {
Derived
doesn't have default constructor; you need to pass the argument to it for constructing, otherwise std::make_shared<T>()
would fail. You can change MakeVector
to the following with parameter 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;
}
then use it like
// Create a vector of shared_ptr to 5 Derived objects:
Foo foo2 {foo2Size, MakeVector<Derived>(foo2Size, 42)};