I have a struct with deleted copy and move constructors and operators, but I want to add this struct to a container. How can I solve this problem?
class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(NonCopyable &&) = default;
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
NonCopyable& operator=(NonCopyable&&) = default;
};
class NonMovable {
public:
NonMovable() = default;
NonMovable(NonMovable &&) = delete;
NonMovable(const NonMovable&) = default;
NonMovable& operator=(const NonMovable&) = default;
NonMovable& operator=(NonMovable&&) = delete;
};
struct Data : NonCopyable, NonMovable
{
Data(std::string str, int data)
: m_str(std::move(str)), m_data(data) {}
private:
std::string m_str;
int m_data;
};
int main(int argc, char** argv)
{
std::unordered_map<std::string, Data> table;
table.emplace("test", Data{"data",10});
return 0;
}
Error:
/Library/Developer/CommandLineTools/usr/bin/../include/c /v1/memory:1881:31: error: no matching constructor for initialization of 'std::__1::pair<const std::__1::basic_string<char>, Data>'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
CodePudding user response:
table.emplace("test", Data{"data",10})
will still call the move constructor of Data
, you need to use std::piecewise_construct
to construct the pair
:
std::unordered_map<std::string, Data> table;
table.emplace(std::piecewise_construct,
std::make_tuple("test"),
std::make_tuple("data",10));
According to cppreference:
template<class... Args1, class... Args2> constexpr pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
Forwards the elements of
first_args
to the constructor offirst
and forwards the elements ofsecond_args
to the constructor ofsecond
. This is the only non-default constructor that can be used to create a pair of non-copyable non-movable types.
CodePudding user response:
A more terse alternative to piecewise_construct
:
table.try_emplace("test", "data", 10);