[英]Why the MVS compiler can convert argument 'myStruct' to 'myStruct &'. And did not file error C2664: cannot convert 'myStruct' to 'myStruct &'
[英]C++: insert element into std::map<MyStruct> where MyStruct can only be aggregate initialized and contains const unique pointers
這是我正在嘗試做的事情以及我嘗試過的事情:
#include <memory>
#include <map>
#include <string>
using namespace std;
struct MyStruct {
const unique_ptr<int> a;
const unique_ptr<int> b;
};
int main() {
auto a = make_unique<int>(7);
auto b = make_unique<int>(5);
map<string, MyStruct> myMap;
myMap["ab"] = { move(a), move(b) }; // nope
myMap.insert("ab", { move(a), move(b) }); // nope
myMap.emplace("ab", { move(a), move(b) }); // nope
myMap.try_emplace("ab", { move(a), move(b) }); // nope
// EDIT 1:
myMap.emplace(piecewise_construct,
forward_as_tuple("ab"),
forward_as_tuple(move(a), move(b))
); // nope
// EDIT 2:
// works in C++20 as there is now a standard ctor for MyStruct:
myMap.try_emplace("ab", move(a), move(b));
return 0;
}
我明白為什么這些都不起作用,但是有沒有辦法在不修改 MyStruct 的情況下將元素插入 myMap?
兩個都
myMap.emplace(piecewise_construct,
forward_as_tuple("ab"),
forward_as_tuple(move(a), move(b))
);
和
myMap.try_emplace("ab", move(a), move(b));
應該在 C++20 中工作。 您需要就地構建該對,因為由於MyStruct
它將不可復制且不可移動。 這只剩下成員函數的emplace
族。 在emplace
中使用花括號初始化器列表永遠無法工作,因為emplace
僅轉發 arguments,但無法推斷 arguments 的類型。
在 C++20 之前,這些成員函數也不起作用,因為它們在內部使用帶括號的直接初始化。 然而, MyStruct
沒有與這兩個 arguments 匹配的構造函數。在 C++20 中,帶括號的初始化器也可以進行聚合初始化,這將起作用,因為MyStruct
是一個聚合。
我認為在不更改MyStruct
或為其添加隱式轉換的情況下,不可能在 C++20 之前向 map 添加元素,因為它只能被聚合初始化,但必須是emplace
構造的,它不會' t 支持聚合初始化。
唯一的例外應該是默認初始化。 例如
myMap.emplace(piecewise_construct,
forward_as_tuple("ab"),
forward_as_tuple()
);
也應該在 C++20 之前工作,因為MyStruct
是可默認構造的。
可以添加隱式轉換來進行聚合初始化,例如:
struct A {
std::unique_ptr<int> a;
std::unique_ptr<int> b;
operator MyStruct() && {
return {std::move(a), std::move(b)};
}
};
//...
myMap.emplace("ab", A{ std::move(a), std::move(b) });
這可能會在編譯器的 C++17 模式下工作,盡管它在技術上是不正確的,因為強制復制省略不適用於轉換運算符的初始化。 請參閱CWG 2327 。
至於MyStruct
的變化:特別是上面引用的兩個例子如果你添加一個匹配的構造函數也應該在 C++20 之前工作:
struct MyStruct {
MyStruct(std::unique_ptr<int> a_, std::unique_ptr<int> b_) : a(std::move(a_)), b(std::move(b_)) { }
const std::unique_ptr<int> a;
const std::unique_ptr<int> b;
};
移動語義不適用於常量數據。
你需要重載你的結構運算符。 https://en.cppreference.com/w/cpp/language/rule_of_three
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.