[英]Why explicit-ness of std::pair's heterogeneous "move"-constructor changed in C++17?
請原諒令人費解的標題,並考慮以下代碼:
#include <memory>
#include <utility>
using X = std::unique_ptr<int>;
using A = std::pair<int, const X>;
using B = std::pair<int, X>;
static_assert(std::is_constructible<A, B>::value, "(1)"); // Ok.
static_assert(std::is_convertible<B, A>::value, "(2)"); // Rejected by GCC and Clang, in C++14 and before.
static_assert(std::is_constructible<const X, X>::value, "(3)"); // Ok.
static_assert(std::is_convertible<X, const X>::value, "(4)"); // Ok.
簡而言之,來自 std::pair<int, std::unique_ptr<int>> 類型右值的std::pair<int, std::unique_ptr<int>>
std::pair<int, const std::unique_ptr<int>>
的構造函數在 C++14 中是explicit
的,和隱式和 C++17 及更高版本。 這種差異從何而來?
只有 libstdc++ 和 libc++ 展示了這種行為。 在 MSVC 的庫中,構造函數始終是隱式的。
為什么它在 C++14 中是explicit
的? 我沒有看到任何與cppreference相關的內容(構造函數 (6))。
相關的構造函數在 C++17 之前也沒有explicit
。
pre-C++17 模式下的 GCC 和 Clang 實際上正在考慮std::is_convertible<B, A>::value
false 因為A
的移動構造函數被隱式刪除。
移動構造函數被隱式刪除,因為const std::unique_ptr
不能被移動或復制。
在 C++17 之前,移動構造函數需要滿足std::is_convertible<B, A>::value
,因為它測試是否有以下形式的函數
A test() {
return std::declval<B>();
}
會形成良好的。 return 語句從操作數復制初始化A
返回值,在 C++17 復制初始化之前,如有必要,復制初始化始終涉及轉換為目標類型的臨時對象,然后從臨時對象直接初始化目標。 該直接初始化將使用A
的移動構造函數。 編譯器可以忽略移動,但移動構造函數必須仍然可用。
由於 C++17 強制復制省略適用,甚至在概念上,復制初始化不再包含通過移動構造函數進行的直接初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.