簡體   English   中英

為什么顯式構造被視為(隱式)縮小轉換?

[英]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

我的問題:

  1. 為什么uint32_t { x }不如static_cast<uint32_t>(x)明確?
  2. 為什么這對 clang 比 GCC 更嚴重,值得一個錯誤?

為什么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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM