如何初始化静态映射,其中值为std::unique_ptr
?
static void f()
{
static std::map<int, std::unique_ptr<MyClass>> = {
{ 0, std::make_unique<MyClass>() }
};
}
当然不行(
std::unique_ptr
的拷贝构造函数被删除了)。有可能吗?
如何初始化静态映射,其中值为std::unique_ptr
?
static void f()
{
static std::map<int, std::unique_ptr<MyClass>> = {
{ 0, std::make_unique<MyClass>() }
};
}
std::unique_ptr
的拷贝构造函数被删除了)。std::initializer-list
构造对象会复制其内容。(std::initializer_list
中的对象天然为 const
)。
要解决这个问题:您可以从一个单独的函数中初始化映射表...std::map<int, std::unique_ptr<MyClass>> init(){
std::map<int, std::unique_ptr<MyClass>> mp;
mp[0] = std::make_unique<MyClass>();
mp[1] = std::make_unique<MyClass>();
//...etc
return mp;
}
然后称之为
static void f()
{
static std::map<int, std::unique_ptr<MyClass>> mp = init();
}
编写定制的创建代码似乎很无聊,而且会影响代码的清晰度。
这里提供了相当高效的通用容器初始化代码。它将您的数据存储在临时std::array
中,就像初始化列表一样,但它是移动而不是使其成为const
。
make_map
接受偶数个元素,第一个是键,第二个是值。
template<class E, std::size_t N>
struct make_container_t{
std::array<E,N> elements;
template<class Container>
operator Container()&&{
return {
std::make_move_iterator(begin(elements)),
std::make_move_iterator(end(elements))
};
}
};
template<class E0, class...Es>
make_container_t<E0, 1+sizeof...(Es)>
make_container( E0 e0, Es... es ){
return {{{std::move(e0), std::move(es)...}}};
}
namespace details{
template<std::size_t...Is, class K0, class V0, class...Ts>
make_container_t<std::pair<K0,V0>,sizeof...(Is)>
make_map( std::index_sequence<Is...>, std::tuple<K0&,V0&,Ts&...> ts ){
return {{{
std::make_pair(
std::move(std::get<Is*2>(ts)),
std::move(std::get<Is*2+1>(ts))
)...
}}};
}
}
template<class...Es>
auto make_map( Es... es ){
static_assert( !(sizeof...(es)&1), "key missing a value? Try even arguments.");
return details::make_map(
std::make_index_sequence<sizeof...(Es)/2>{},
std::tie( es... )
);
}
static std::map<int, std::unique_ptr<MyClass>> bob =
make_map(0, std::make_unique<MyClass>());
涵盖拼写错误的内容除外。
实时示例。
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static std::map<int, std::unique_ptr<MyClass>> mp = [](auto& model)
{
auto mp = std::decay_t<decltype(model)> {};
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return mp;
}(mp);
return mp;
}
int main()
{
auto& m = f();
}
这里还有另一种方式。在这种情况下,我们将临时对象传递到lambda中,并依靠复制省略/RVO。
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static auto mp = [](auto mp)
{
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return mp;
}(std::map<int, std::unique_ptr<MyClass>>{});
return mp;
}
int main()
{
auto& m = f();
}
还有一种方法,使用可变 lambda 中的 lambda 捕获。
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static auto mp = [mp = std::map<int, std::unique_ptr<MyClass>>{}]() mutable
{
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return std::move(mp);
}();
return mp;
}
int main()
{
auto& m = f();
}