C ++初始化对象的非静态成员数组
Posted
技术标签:
【中文标题】C ++初始化对象的非静态成员数组【英文标题】:C++ Initializing non-static member array of objects 【发布时间】:2018-07-19 11:40:23 【问题描述】:我正在尝试在不使用 STL 的情况下初始化类的私有成员数组(因为我正在使用的 Arduino 微控制器平台不支持它)。这意味着没有std::array
或std::initializer_list
等。
以下使用 gcc 5.4.0 和 avr-gcc 4.9.2 正确编译,但 that seems to be a bug。 Clang 抛出一个错误,说 error: array initializer must be an initializer list
(如预期的那样)。
代码
#include <iostream>
#define PRINTFN() std::cout << __PRETTY_FUNCTION__ << std::endl
class Object
public:
Object(int number) : number(number) PRINTFN();
Object(const Object &o) : number(o.number) PRINTFN();
void print() std::cout << "The number is " << number << std::endl;
private:
const int number;
;
template <size_t N>
class ManyObjects
public:
ManyObjects(const Object(&objects)[N]) : objects(objects)
void print()
for (Object &object : objects)
object.print();
private:
Object objects[N];
;
int main()
ManyObjects<3> many = 1, 2, 3;
many.print();
输出
Object::Object(int)
Object::Object(int)
Object::Object(int)
Object::Object(const Object&)
Object::Object(const Object&)
Object::Object(const Object&)
The number is 1
The number is 2
The number is 3
初始化objects
的正确方法是什么?还是在给定的约束下是不可能的?
【问题讨论】:
你允许 Object 有赋值运算符吗? @UmNyobe,当然,如果需要的话。 你不能使用::boost::array
或者自编码数组包装器吗?
【参考方案1】:
您可以使用可变参数模板:
在ManyObjects
类中:
template <typename... _Args>
ManyObjects(_Args&&... arguments) :
objects arguments...
更多here
【讨论】:
这确实有效,但它的可读性较差,对最终用户不太友好(Arduino 平台针对初学者),因为它不会将列表的参数与任何其他参数分开到ManyObjects
构造函数。我想我可以用我原来的类包装存储对象的类,但我并不完全相信。
@tttapa, template <typename... _Args> ManyObjects (int arg1, char arg2, _Args&&... arguments)
- 如果你想向 ManyObjects 构造函数添加一些其他参数。
注意可变参数模板构造函数,因为ManyObjects(ManyObjects&)
将匹配模板而不是复制构造函数。【参考方案2】:
是的,可变参数模板可以工作,但有点棘手:
template <size_t N>
class ManyObjects
public:
template<typename T, typename ...Args>
ManyObjects(const T& x, Args&&... args) : objectsx, args...
private:
Object objects[N];
;
int main()
ManyObjects<3> many1, 2, 3;
ManyObjects<3> copymanymany;
copymany.print();
对于任何固定的 N 都可以解释为:
template <size_t N=3>
class ManyObjects
public:
ManyObjects(int x, int y, int z) : objectsx, y, z
...
;
这里有什么:
-
由于构造函数
Object(int)
的定义,无法默认初始化对象
对象赋值运算符被隐式删除,因为 number 是 const
因此,任何数组Object arr[N]
都必须使用聚合初始化显式初始化。
我想到的唯一方法是通过可变参数模板执行扩展初始化。
为了防止匹配复制构造函数,您可以在参数包之外指定第一个参数。您松开了大小 0 的构造,可以通过模板特化来启用它。
ManyObjects<0> noneof;
noneof.print();
【讨论】:
注意可变参数模板构造函数,因为ManyObjects(ManyObjects&)
将匹配模板而不是复制构造函数。
如何定义复制构造函数?
事实上,模板可变参数构造函数应该是 SFINAE 以排除与复制/移动构造函数匹配的签名:检查大小和第一个参数类型。【参考方案3】:
我最终听从了 VTT 的建议,并创建了自己的数组包装器。
如果有我需要注意的事情或可能的错误等,我很乐意听到一些反馈。
#include <iostream>
class Object
public:
Object(int number) : numbernumber
void print() std::cout << "The number is " << number << std::endl;
private:
const int number;
;
// -------------------------------------------------------------------------- //
template <class T, size_t N> class ArrayWrapper
public:
T &operator[](size_t index) return data[index];
const T &operator[](size_t index) const return data[index];
T *begin() return &data[0];
const T *begin() const return &data[0];
T *end() return &data[N];
const T *end() const return &data[N];
T data[N];
;
// -------------------------------------------------------------------------- //
template <size_t N> class ManyObjects
public:
ManyObjects(const ArrayWrapper<Object, N> &objects, const char *name)
: objectsobjects, namename
void print()
std::cout << name << std::endl;
for (auto &object : objects)
object.print();
private:
ArrayWrapper<Object, N> objects;
const char *name;
;
// -------------------------------------------------------------------------- //
int main()
ManyObjects<3> many = 1, 2, 3, "Many";
many.print();
【讨论】:
以上是关于C ++初始化对象的非静态成员数组的主要内容,如果未能解决你的问题,请参考以下文章