對不起,通用標題,但這是一種思維方式,我無法輕易描述。
假設以下代碼:
struct S
{
S() = default;
int x;
int y;
};
S f()
{
return { 1, 2 };
}
這編譯和作業得很好。我想禁止它,因為它容易出錯(實際代碼要復雜得多)。所以,我嘗試添加
template<typename T>
S(std::initializer_list<T>) = delete;
但你猜怎么著 - 沒有任何變化。在 Visual Studio 2019 上使用 std=c 17 進行測驗。C resharper 將此顯示為錯誤,但 msvc 實際上編譯了它并且它可以作業。
等等,現在變得有趣了。如果S() = default;替換為S() {},則編譯失敗
'S::S<int>(std::initializer_list<int>)': attempting to reference a deleted function
好吧,這看起來與用戶定義的建構式和初始化有關?!有點亂,不過可以理解。
但是等等 - 它變得更有趣 - 保留= default建構式,但創建欄位private也會改變這種行為并猜測 - 該錯誤與不可訪問的成員無關,但它再次顯示了上面的錯誤!
所以,為了使這個洗掉作業,我應該將欄位設為私有或定義我自己的空建構式(忽略未初始化的 x 和 y 欄位,這只是一個簡化的例子),意思是:
struct S
{
S() = default;
// S() {}
template<typename T>
S(std::initializer_list<T>) = delete;
private:
int x;
int y;
};
clang 13 和 GCC 11 的行為方式完全相同,而 GCC 9.3 無法編譯原始代碼(具有=default建構式、公共欄位,但洗掉了初始化串列建構式)。
任何想法會發生什么?
uj5u.com熱心網友回復:
在 C 17 中,S被認為是聚合,因此您沒有呼叫任何建構式,您基本上是直接初始化成員。如果更改為使用 C 20,S則不再被視為聚合,因為規則已更改并且代碼將按預期作業。
更改訪問說明符起作用的原因是聚合的所有非靜態資料成員的訪問說明符需要是公共的。將它們設為非公共意味著您的類不再是聚合,并且您不再獲得聚合初始化,而是嘗試進行串列初始化,但對于已洗掉的建構式卻失敗了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/368066.html
