[英]Constexpr initialization of an array of non-copyable objects?
我想有一個B
類,它具有另一個A
類的3個成員對象。 A
和B
構造函數都是constexpr
。 B
包含的A
是不可復制且不可移動的。 這段代碼正確構建:
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;
}
但是我真的很想將A
類型的3個對象作為一個數組。 如果我嘗試這樣的簡單方法:
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{1}
初始化A
的實例是復制 (或移動)初始化。 大多數編譯器會忽略復制/移動構造函數,甚至不必費心調用復制/移動構造函數,但實際上僅從C ++ 17開始,就不需要復制/移動構造函數。
解決方法是,可以從A
的構造函數中刪除explicit
, A
就地構造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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.