2016-07-05 9 views
4

スタティックマップを初期化するにはどうすればいいですか?値はstd::unique_ptrですか?もちろん値としてunique_ptrを持つstatic std :: mapを初期化する

static void f() 
{ 
    static std::map<int, std::unique_ptr<MyClass>> = { 
     { 0, std::make_unique<MyClass>() } 
    }; 
} 

これは(std::unique_ptrのコピーctorのが削除された)動作しません。

可能ですか?

+0

1つのことに変数名を指定する必要があります。 – Galik

答えて

5

問題は、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; 
} 

...あなたは別の関数からマップを初期化することができます。そして、これを行うにLive On Coliru

+0

'init()'が 'std :: map <...> &&'(rvalue)を返すのであれば違いはありますか?私。右辺値を返す方が良いでしょうか? Upd:rvalueを使用すると、segfault – vladon

+1

@vladonが実行されます。これはパフォーマンスの犠牲を招くだけでなく、バ​​グです。 'rvalue'リファレンスを破壊されたオブジェクトに返します。 [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://ja.cppreference.com/w/cpp/language/copy_elision) – WhiZTiM

1

もう一つの方法はであり、それを参照してください

static void f() 
{ 
    static std::map<int, std::unique_ptr<MyClass>> mp = init(); 
} 
それを呼び出す:あなたの問題を解決するために ラムダを使用してください。別の関数を使用するのと同じですが、マップの初期化をアクションに近づけます。この例では、&と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(); 
} 

これは別の方法です。この場合、一時的にラムダに渡して、コピーelision/RVOに依存しています。さらに別の方法では、可変ラムダにおけるラムダ捕捉を使用する。

#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(); 
} 
1

特注のコードを書くことは退屈で分かりやすくなります。

これは、合理的に効率的な汎用コンテナ初期化コードです。イニシャライザーのようにデータを一時的にstd::arrayに保存しますが、それはconstの代わりに出ます。

make_mapは偶数の要素を取ります。最初の要素は2番目の値をキーします。

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>()); 

関連する問題