簡體   English   中英

使用純右值直接初始化:MSVC 中的錯誤?

[英]Direct initialization with prvalue: Bug in MSVC?

考慮以下代碼:

struct S
{
    S(int, double) {}
    explicit S(const S&) {}
    explicit S(S&&) {}
};

void i_take_an_S(S s) {}

S i_return_an_S() { return S{ 4, 2.0 }; }

int main()
{
    i_take_an_S(i_return_an_S());
}

使用 '-std=c++17' 標志,g++ 和 clang++ 都可以很好地編譯此代碼。 但是,MSVC(帶有 /std:c++17 標志)報告

“錯誤 C2664:‘void i_take_an_S(S)’:無法將參數 1 從‘S’轉換為‘S’”

作為編譯錯誤,帶有附加說明

“結構‘S’的構造函數被聲明為‘顯式’”。

根據 C++17 的初始化規則(第 3 點的解釋),對於i_take_an_SS參數的初始化,不應考慮S的復制構造函數; S(int, double)應該被直接列表初始化選擇為精確匹配。

這可能是 MSVC 中的錯誤嗎?

是的,MSVC 在這里似乎是錯誤的。

一般從C++17開始,初始化規則是S s S{ 4, 2.0 }會直接初始化function的參數Ss。 (強制復制省略)

然而有一個例外。 如果 class 類型僅刪除或微不足道的復制/移動構造函數和析構函數(以及至少一個以前未刪除的),則允許實現在 function 參數或返回值中引入副本。

您顯式聲明復制和移動構造explicit不會改變它們是復制/移動構造函數。 因為您沒有使用= default來定義它們,所以它們並非微不足道。 因此,特殊權限不適用,MSVC 嘗試執行復制是錯誤的。

此外,這種特殊類型的副本忽略了可訪問性和重載解析,因此即使執行explicit也不應該相關,請參閱[class.temporary]/3


然而,當精確地執行復制省略會影響 ABI,所以如果這是 MSVC 的 ABI 中的缺陷,那么它可能不容易修復。

這可能是 MSVC 中的錯誤嗎?

是的,MSVC 拒絕代碼是錯誤的。

return 語句return S{ 4, 2.0 }的操作數S{ 4, 2.0 }S類型的純右值,從 C++17 開始,由於強制復制 elison ,function i_take_an_S的名為s的參數直接構造(不使用任何復制從S{ 4, 2.0 }移動 ctor)。


這可以從復制 elison中看出:

在以下情況下,編譯器需要省略 class 對象的復制和移動構造,即使復制/移動構造函數和析構函數具有可觀察到的副作用。 對象直接構建到存儲中,否則它們將被復制/移動到 復制/移動構造函數不需要存在或可訪問:

在返回語句中,當操作數是與 function 返回類型相同的 class 類型(忽略 cv 限定)的純右值時:

 T f() { return T(); } f(); // only one call to default constructor of T

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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