c++ - 一个不可复制对象数组的constexpr初始化?
问题描述
我想要一个B
有另一个类的 3 个成员对象的类A
。A
both和B
are 的构造函数constexpr
。A
- 包含在里面B
- 是不可复制和不可移动的。此代码正确构建:
class A
{
public:
constexpr explicit A(int a) {}
A(const A&) = delete;
A(A&&) = delete;
};
class B
{
public:
constexpr B() :
a0{0},
a1{1},
a2{2}
{}
private:
A a0;
A a1;
A a2;
};
int main()
{
B b;
}
但是我真的很想将 3 个类型的对象A
作为一个数组。如果我尝试这样的简单方法:
class A
{
public:
constexpr explicit A(int a) {}
A(const A&) = delete;
A(A&&) = delete;
};
class B
{
public:
constexpr B() :
a{A{1}, A{2}, A{3}}
{}
private:
A a[3];
};
int main()
{
B b;
}
无法构建:
$ g++ a.cpp
a.cpp: In constructor ‘constexpr B::B()’:
a.cpp:21:22: error: use of deleted function ‘A::A(A&&)’
a{A{1}, A{2}, A{3}}
^
a.cpp:13:2: note: declared here
A(A&&) = delete;
^
a.cpp:21:22: error: use of deleted function ‘A::A(A&&)’
a{A{1}, A{2}, A{3}}
^
a.cpp:13:2: note: declared here
A(A&&) = delete;
^
a.cpp:21:22: error: use of deleted function ‘A::A(A&&)’
a{A{1}, A{2}, A{3}}
^
a.cpp:13:2: note: declared here
A(A&&) = delete;
^
a.cpp:28:2: error: member ‘B::a’ must be initialized by mem-initializer in ‘constexpr’ constructor
}
^
a.cpp:32:7: note: declared here
A a[3];
^
不做可动能解决A
吗?
编辑:
正如@rustyx 所建议的,我对代码进行了一些更改,它适用于 C++11 和 C++17(带有explicit
)。然而——像往常一样——真正的代码要复杂一些。假设它A
真的是不可移动和不可复制的,假设它有一个析构函数。
class A
{
public:
constexpr explicit A(int a) {}
~A() {}
A(const A&) = delete;
A(A&&) = delete;
};
class B
{
public:
constexpr B() :
a{A{1}, A{2}, A{3}}
{}
private:
A a[3];
};
int main()
{
B b;
}
即使使用 C++17 也会失败:
g++ a.cpp -std=c++17
a.cpp: In constructor ‘constexpr B::B()’:
a.cpp:14:22: error: use of deleted function ‘A::A(A&&)’
a{A{1}, A{2}, A{3}}
^
a.cpp:7:2: note: declared here
A(A&&) = delete;
^
a.cpp:14:22: error: non-constant array initialization
a{A{1}, A{2}, A{3}}
^
a.cpp:15:3: error: use of deleted function ‘A::A(A&&)’
{}
^
a.cpp:7:2: note: declared here
A(A&&) = delete;
^
如果A
的构造函数不是,它也会失败explicit
。如果我删除析构函数,那么它就可以工作,但是如果析构函数必须在那里呢?这个特定的数组初始化问题是否有解决方案,或者我在这里不走运?
解决方案
严格来说,初始化A
from的实例A{1}
是复制(或移动)初始化。大多数编译器省略了复制/移动,甚至不打扰调用复制/移动构造函数,但仅从 C++17 开始实际上不需要存在复制/移动构造函数。
作为一种解决方法,您可以explicit
从s 构造函数中删除并就地A
构造s:A
class A
{
public:
constexpr A(int a) {}
A(const A&) = delete;
A(A&&) = delete;
};
class B
{
public:
constexpr B() :
a{{1}, {2}, {3}}
{}
private:
A a[3];
};
int main()
{
B b;
}
=== 编辑 ===(回应问题编辑)
假设 A 真的是不可移动和不可复制的,假设它有一个析构函数。
我能想到的唯一可能的解决方法是核选项又名放置新:
#include <memory>
#include <type_traits>
class A
{
public:
constexpr A(int a) {}
A(const A&) = delete;
A(A&&) = delete;
~A() {}
};
class B
{
public:
B() {
new (std::addressof(a[0])) A(1);
new (std::addressof(a[1])) A(2);
new (std::addressof(a[2])) A(3);
}
A& getA(size_t offset) { return reinterpret_cast<A*>(a)[offset]; }
private:
std::aligned_storage<sizeof(A), alignof(A)>::type a[3];
};
int main()
{
B b;
}
推荐阅读
- android - Firebase Cloud Functions 在写入后立即删除数据
- python - 使用 Kivy/Buildozer 后在 Android 上打开我的应用程序时遇到问题
- javascript - 如何在 react-native 中替换 TextInput 中的字符串
- ios - 按社交网络 iOS 应用程序中的相互连接和 Firestore 中的数据存储进行排序
- pdf - PDF字体对象的/Widths数组是否是冗余信息?
- node.js - 节点 Cron / 节点计划并不总是在特定日期工作
- r - 用于R中的乘法比较的prop.test
- django - 附加到一个字段的多个子字段,以及如何为用户提供添加许多这些字段的可能性
- javascript - 如何获取 cURL 代码以在 Windows 10 上编译?
- chat - 如何在一个话语中处理多个问题?