Both
myMap.emplace(piecewise_construct,
forward_as_tuple("ab"),
forward_as_tuple(move(a), move(b))
);
and
myMap.try_emplace("ab", move(a), move(b));
should work in C++20. You need to construct the pair in-place, because it will be non-copyable and non-movable due to MyStruct
. This leaves only the emplace
family of member functions. Using a braced initializer list in emplace
can never work because emplace
only forwards arguments, but wouldn't be able to deduce types for arguments.
Before C++20, these member functions also won't work, because they internally use direct-initialization with parentheses. MyStruct
however has no constructor matching the two arguments. In C++20 parenthesized initializers can also do aggregate initialization and that will work, since MyStruct
is an aggregate.
I don't think there is any possibility to add an element to the map before C++20 without change of MyStruct
or adding an implicit conversion for it, because it can only be aggregate-initialized, but must be emplace
constructed which doesn't support aggregate-initialization.
The only the exception to that should be default initialization. For example
myMap.emplace(piecewise_construct,
forward_as_tuple("ab"),
forward_as_tuple()
);
should work also before C++20, because MyStruct
is default-constructible.
An implicit conversion could be added to do aggregate initialization, for example:
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) });
This will probably work in C++17 mode on compilers, although it is technically not correct as mandatory copy elision doesn't apply to initialization by conversion operator. See CWG 2327.
As for changes of MyStruct
: In particular the two examples quoted above should also work pre-C++20 if you add a matching constructor:
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;
};