[英]Why is an explicit construction considered an (implicit) narrowing conversion?
考慮以下代碼:
uint32_t foo(uint64_t x ) {
auto y = uint32_t { x };
return y;
}
它被認為是一種縮小轉換,編譯器不得不警告我 (GCC 9) 甚至聲明錯誤 (clang 9): GodBolt 。
我的問題:
uint32_t { x }
不如static_cast<uint32_t>(x)
明確?為什么
uint32_t { x }
不如static_cast<uint32_t>(x)
明確?
這不是不那么明確,只是不允許。 進行直接或復制列表初始化時不允許縮小轉換。 當你做auto y = uint32_t { x };
您正在使用縮小轉換直接列表初始化y
。 (保證復制省略意味着這里沒有臨時了)
為什么這對 clang 比 GCC 更嚴重,值得一個錯誤?
這取決於實施者。 顯然,clang 想要更嚴格並發出硬錯誤,但兩者都很好。 該標准只要求給出診斷消息,警告或錯誤涵蓋了這一點。
添加到@NathanOliver 的答案 - 如果我們像這樣構造 32 位整數,警告和錯誤就會消失:
uint32_t foo(uint64_t x ) {
auto y = uint32_t(x);
return y;
}
所以,這里的(x)
和{x}
在語義上不是等價的(即使最終會調用相同的構造函數,如果它是一個類)。 標准中的無限制保證顯然僅適用於列表初始化 IIANM。
因此,如果您想格外小心(或者如果您不想被打擾,則使用括號),這是使用花括號初始化的動機。
從https://en.cppreference.com/w/cpp/language/list_initialization :
縮小轉化范圍
列表初始化通過禁止以下內容來限制允許的隱式轉換:
...
- 從整數或無作用域枚舉類型轉換為不能表示原始所有值的整數類型,除非源是一個常量表達式,其值可以准確地存儲在目標類型中
這聽起來像 clang 在這里比 gcc 更符合(盡管要注意我不是語言律師)*:標准規定,如果您使用初始化器列表,則不會有任何縮小轉換的危險。 這是一個有意識的設計選擇,以彌補語言中內置的相當混雜的隱式轉換 - 並且您在示例中明確說明它的方式是一種附帶的煩惱。
編輯:* 並沒有花很長時間 - 根據 NathanOliver 的回答,cppreference 中的“不允許”在標准中轉換為“依賴於實現者”。 這就是我不檢查來源的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.