[英]Function template to populate a vector of shared_ptr to Base & Derived objects
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. 这里的目标是创建一个请求数量的
Base
或Derived
对象,并将一个带有shared_ptr
的std::vector
填充到这些对象。
I am getting a compiler error on the for
statement: 我在
for
语句上遇到编译器错误:
error: there are no arguments to 'begin' that depend on a template parameter, so a declaration of 'begin' must be available [-fpermissive]
错误:“begin”没有依赖于模板参数的参数,因此'begin'的声明必须可用[-fpermissive]
If I use a std::iterator
with begin
and end
, unfortunately the iterator becomes invalid with each push_back
. 如果我使用带有
begin
和end
的std::iterator
,不幸的是迭代器对每个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
. 您不能在
std::size_t
上使用基于范围的for循环 。 You could change 你可以改变
for(auto &i : numElements) {
to 至
for (std::size_t i = 0; i < numElements; i++) {
Derived
doesn't have default constructor; Derived
没有默认构造函数; you need to pass the argument to it for constructing, otherwise std::make_shared<T>()
would fail. 你需要将参数传递给它进行构造,否则
std::make_shared<T>()
会失败。 You can change MakeVector
to the following with parameter pack : 您可以使用参数包将
MakeVector
更改为以下内容:
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)};
The numElements
is a std::size_t
type which has no begin
and end
iterator defined (which is defined for standard containers and user-defined types, not for primitive types), which are required for a range-based for
loop . numElements
是一个std::size_t
类型,它没有定义begin
和end
迭代器(为标准容器和用户定义的类型定义,而不是为基本类型定义),这是基于范围的for
循环所必需的。 Therefore you need either a classical for
loop 因此,您需要一个经典的
for
循环
for(std::size_t index{ 0 }; index < numElements; index ++)
{
vec.push_back(std::make_shared<T>());
}
or simply a while
loop: 或者只是一个
while
循环:
while(numElements--)
{
vec.push_back(std::make_shared<T>());
}
Secondly, as @songyuanyao pointed out, Derived
class must have a default
constructor for the MakeVector
to work. 其次,正如@songyuanyao指出的那样,
Derived
类必须有一个default
构造函数才能使MakeVector
工作。 You can default one like: 您可以默认如下:
Derived() = default;
// or
// Derived(double z0 = 0.0): Base{}, z{ z0 } {}
or the best like in @songyuanyao 's answer , provide an extra varidic-template-args for the constructor parameters. 或@songyuanyao 的答案中最好的 ,为构造函数参数提供额外的varidic-template-args。
for(auto &i : numElements) { // Compiler error occurs here.
vec.push_back(std::make_shared<T>());
}
The for range is for container. 适用范围适用于容器。 Here numElements is a number, use a classical for loop.
这里numElements是一个数字,使用经典的for循环。
for(std::size_t i = 0; i < numElements; i++) {
vec.push_back(std::make_shared<T>());
}
You can't use a range-based for loop on arbitrary type. 您不能在任意类型上使用基于范围的for循环。 The type should work with definition from standard,
该类型应符合标准的定义,
// for ( range_declaration : range_expression ) loop_statement
{
auto && __range = range_expression ;
for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin)
{
range_declaration = *__begin;
loop_statement
}
}
ie it should have defined begin
, end
, as well as increment, dereference and comparison operators, which isn't a case for trivial integral types. 即它应该定义
begin
, end
,以及增量,解除引用和比较运算符,这不是普通整数类型的情况。 In your case usual for is required, unless you want to define a type that describes range. 在您需要的情况下,除非您想要定义描述范围的类型。
for (auto i = 0; i < numElements; ++i)
Ofc, one may be creative and use range for with just about any type. Ofc,一个人可能很有创意并且几乎可以使用任何类型的范围。 Something like this (this is no way a recommendation, just an example):
像这样的东西(这不是一个推荐,只是一个例子):
#include <utility>
#include <iostream>
// Those should be in same namespace
template<class T, template<typename,T,T> class iT, T _b, T _e>
iT<T,_b,_e> begin(iT<T,_b,_e> v)
{
return iT<T,_b,_e> {_b};
}
template<class T, template<typename,T,T> class iT, T _b, T _e>
iT<T,_b,_e> end(iT<T,_b,_e> v)
{
return iT<T,_b,_e> {_e};
}
template<class T, T begin, T end>
struct range {
static const T _begin = T{begin};
static const T _end = T{end};
T value;
range& operator++() { //prefix
++value;
return *this;
}
T operator+(T inc) {
return range<T,begin,end>{value + inc};
}
T operator-(T inc) {
return range<T,begin,end>{value - inc};
}
T operator*() {return value;}
bool operator != (range arg) { return value != arg.value; }
};
template<class T, T _b, T _e>
range<T,_b,_e> operator++(range<T,_b,_e> &v, int) //postfix
{
range<T,_b,_e> result {v};
++v;
return result;
}
int main()
{
typedef range<size_t, 3, 10> SomeRange;
for(auto i : SomeRange())
{
std::cout << i << std::endl;
}
}
Derived
class needs at least a default constructor, or your populating method MakeVector
should be changed to emplace proper values Derived
类至少需要一个默认构造函数,或者应该将您的填充方法MakeVector
更改为赋予正确的值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.