用于将 shared_ptr 向量填充到 Base & Derived 对象的函数模板
Function template to populate a vector of shared_ptr to Base & Derived objects
考虑以下几点:
#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)};
}
这里的objective是创建请求数量的Base
或Derived
个对象,并用shared_ptr
填充一个std::vector
到这些对象.
我在 for
语句中遇到编译器错误:
error: there are no arguments to ‘begin’ that depend on a template
parameter, so a declaration of ‘begin’ must be available
[-fpermissive]
如果我将 std::iterator
与 begin
和 end
一起使用,不幸的是迭代器对每个 push_back
都无效。无论如何,我需要迭代特定次数来填充向量。
这个问题有明显的解决方案吗?
for(auto &i : numElements) { // Compiler error occurs here.
vec.push_back(std::make_shared<T>());
}
适用于容器的范围。这里 numElements 是一个数字,使用经典的 for 循环。
for(std::size_t i = 0; i < numElements; i++) {
vec.push_back(std::make_shared<T>());
}
numElements
是一个 std::size_t
类型,它没有定义 begin
和 end
迭代器(它是为标准容器和用户定义类型定义的,而不是为原始类型),这是 range-based for
loop. Therefore you need either a classical for
loop
所必需的
for(std::size_t index{ 0 }; index < numElements; index ++)
{
vec.push_back(std::make_shared<T>());
}
或者只是一个 while
循环:
while(numElements--)
{
vec.push_back(std::make_shared<T>());
}
其次,正如@songyuanyao所指出的,Derived
class必须有一个default
构造函数用于MakeVector
工作。您可以默认一个:
Derived() = default;
// or
// Derived(double z0 = 0.0): Base{}, z{ z0 } {}
或 @songyuanyao 's answer 中最好的,为构造函数参数提供额外的 varidic-template-args。
您不能在 std::size_t
上使用 range-based for loop。你可以改变
for(auto &i : numElements) {
至
for (std::size_t i = 0; i < numElements; i++) {
Derived
没有默认构造函数;您需要将参数传递给它进行构造,否则 std::make_shared<T>()
将失败。您可以使用 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;
}
然后像这样使用它
// Create a vector of shared_ptr to 5 Derived objects:
Foo foo2 {foo2Size, MakeVector<Derived>(foo2Size, 42)};
您不能对任意类型使用基于范围的 for 循环。该类型应符合标准定义,
// 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
}
}
即它应该已经定义了 begin
、end
以及递增、取消引用和比较运算符,这不是普通整数类型的情况。在您的情况下,通常需要 for ,除非您想定义一个描述范围的类型。
for (auto i = 0; i < numElements; ++i)
Ofc,一个人可能有创意,并且可以使用几乎任何类型的范围。像这样的东西(这不是推荐,只是一个例子):
#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 至少需要一个默认构造函数,或者您的填充方法 MakeVector
应该更改为放置适当的值
考虑以下几点:
#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)};
}
这里的objective是创建请求数量的Base
或Derived
个对象,并用shared_ptr
填充一个std::vector
到这些对象.
我在 for
语句中遇到编译器错误:
error: there are no arguments to ‘begin’ that depend on a template parameter, so a declaration of ‘begin’ must be available [-fpermissive]
如果我将 std::iterator
与 begin
和 end
一起使用,不幸的是迭代器对每个 push_back
都无效。无论如何,我需要迭代特定次数来填充向量。
这个问题有明显的解决方案吗?
for(auto &i : numElements) { // Compiler error occurs here.
vec.push_back(std::make_shared<T>());
}
适用于容器的范围。这里 numElements 是一个数字,使用经典的 for 循环。
for(std::size_t i = 0; i < numElements; i++) {
vec.push_back(std::make_shared<T>());
}
numElements
是一个 std::size_t
类型,它没有定义 begin
和 end
迭代器(它是为标准容器和用户定义类型定义的,而不是为原始类型),这是 range-based for
loop. Therefore you need either a classical for
loop
for(std::size_t index{ 0 }; index < numElements; index ++)
{
vec.push_back(std::make_shared<T>());
}
或者只是一个 while
循环:
while(numElements--)
{
vec.push_back(std::make_shared<T>());
}
其次,正如@songyuanyao所指出的,Derived
class必须有一个default
构造函数用于MakeVector
工作。您可以默认一个:
Derived() = default;
// or
// Derived(double z0 = 0.0): Base{}, z{ z0 } {}
或 @songyuanyao 's answer 中最好的,为构造函数参数提供额外的 varidic-template-args。
您不能在
std::size_t
上使用 range-based for loop。你可以改变for(auto &i : numElements) {
至
for (std::size_t i = 0; i < numElements; i++) {
Derived
没有默认构造函数;您需要将参数传递给它进行构造,否则std::make_shared<T>()
将失败。您可以使用 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; }
然后像这样使用它
// Create a vector of shared_ptr to 5 Derived objects: Foo foo2 {foo2Size, MakeVector<Derived>(foo2Size, 42)};
您不能对任意类型使用基于范围的 for 循环。该类型应符合标准定义,
// 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
}
}
即它应该已经定义了 begin
、end
以及递增、取消引用和比较运算符,这不是普通整数类型的情况。在您的情况下,通常需要 for ,除非您想定义一个描述范围的类型。
for (auto i = 0; i < numElements; ++i)
Ofc,一个人可能有创意,并且可以使用几乎任何类型的范围。像这样的东西(这不是推荐,只是一个例子):
#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 至少需要一个默认构造函数,或者您的填充方法 MakeVector
应该更改为放置适当的值