[英]Is a defaulted constructor/assignment noexcept/constexpr by default?
[英]Declaring defaulted assignment operator as constexpr: which compiler is right?
考慮
struct A1 {
constexpr A1& operator=(const A1&) = default;
~A1() {}
};
struct A2 {
constexpr A2& operator=(const A2&) = default;
~A2() = default;
};
struct A3 {
~A3() = default;
constexpr A3& operator=(const A3&) = default;
};
GCC和MSVC接受所有三種結構。 Clang拒絕A1
和A2
(但接受A3
),並顯示以下錯誤消息:
<source>:2:5: error: defaulted definition of copy assignment operator is not constexpr constexpr A1& operator=(const A1&) = default; ^ <source>:6:5: error: defaulted definition of copy assignment operator is not constexpr constexpr A2& operator=(const A2&) = default; ^ 2 errors generated.
( 現場演示 )
哪個編譯器是正確的,為什么?
我認為所有三個編譯器都是錯誤的。
未定義為已刪除的顯式默認函數只有在被隱式聲明為
constexpr
時才可以聲明為constexpr
或consteval
。 如果函數在其第一個聲明中顯式默認,則隱式聲明將隱式地認為是constexpr
。
何時復制賦值運算符隱式聲明constexpr
? [class.copy.assign] / 10 :
隱式定義的復制/移動賦值運算符是constexpr if
- X是文字類型,和
- [...]
文字類型的位置,來自[basic.types] / 10 :
類型是文字類型,如果它是:
- [...]
一個可能具有cv限定的類類型,它具有以下所有屬性:
- 它有一個簡單的析構函數,
- [...]
A1
沒有簡單的析構函數,因此它的隱式復制賦值運算符不是constexpr
。 因此,復制賦值運算符格式不正確(gcc和msvc錯誤接受)。
另外兩個很好,這是拒絕A2
的鏗鏘聲。
注意我引用的[dcl.fct.def.default]的最后一位。 如果您明確默認,則實際上不必添加constexpr
。 在可行的情況下隱含着constexpr
。
C ++ 17標准規定:
15.8.2復制/移動賦值運算符[class.copy.assign]
...10對於默認且未定義為已刪除的類X的復制/移動賦值運算符,在使用odr時會隱式定義(6.2)(例如,當通過重載決策選擇它以分配給其類類型的對象時) )或在第一次聲明后明確違約時。 隱式定義的復制/移動賦值運算符是
constexpr
if
(10.1) -X
是文字類型,和
(10.2) - 選擇復制/移動每個直接基類子對象的賦值運算符是constexpr
函數,和
(10.3) - 對於類型(或其數組)的X
每個非靜態數據成員,選擇復制/移動該成員的賦值運算符是constexpr
函數。
復制賦值運算符在兩種情況下滿足上述要求。 在第一種情況下,由於非平凡的析構函數,我們有一個非文字類型。
所以我認為Clang在第二種情況下拒絕代碼是錯誤的。
有一個提交Clang的錯誤標題: 默認的析構函數阻止在默認的復制/移動操作符上使用constexpr,它顯示與OP中的代碼相同的症狀。
錯誤報告的評論說明:
當默認的析構函數被注釋掉(即沒有用戶聲明)時,錯誤就不復存在了。
和
如果在復制賦值運算符之前聲明析構函數,問題也會消失。
對於問題中的代碼也是如此。
正如@YSC所指出的,這里的另一個相關引用是: [dcl.fct.def.default] / 3 ,其中說明:
未定義為已刪除的顯式默認函數只有在被隱式聲明為
constexpr
時才可以聲明為constexpr
或consteval
。 如果函數在其第一個聲明中顯式默認,則隱式聲明將隱式地認為是constexpr
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.