一個如何初始化靜態映射,其中值是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::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();
}
如果'init()'會返回'std :: map <...> &&'(rvalue)會有區別嗎?即返回一個右值會更好嗎?更新:與右值將有一個段錯誤 – vladon
@ vladon,這不僅僅是一個性能perssimization,這也是一個錯誤。您將返回一個對被銷燬對象的「右值」引用。參見[this](http://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement)...在這種情況下,按值返回是非常有效的,因爲它的[肯定(C++ 17)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0。 html)將享受[RVO](http://en.cppreference.com/w/cpp/language/copy_elision) – WhiZTiM
另一種方式做,這是使用lambda。它與使用單獨的函數相同,但將地圖的初始化更接近動作。在這種情況下,我使用了自動&和decltype的組合來避免必須命名地圖的類型,但這僅僅是爲了好玩。
注意,傳遞到拉姆達的說法是到尚未在調用點構造一個對象的引用,所以我們不能引用它以任何方式。它只用於類型扣除。
#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並依賴copy elision/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();
}
書寫定製crestion代碼看起來很無聊,並得到清晰的方式。
這裏是相當高效的通用容器初始化代碼。它像一個初始化器列表那樣將數據存儲在臨時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){
ststic_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>> =
make_map(0, std::make_unique<MyClass>());
...禁止錯別字。
你必須爲一件事提供一個變量名稱。 – Galik