2016-04-05 16 views
3

std::shared_ptr<std::tuple<MyClass, std::mutex>>があります。std :: mutexを他のクラスとstd :: tupleの中に置く方法は?

std::mutexはコピーも移動もできません。どのように初期化するのですか?

+4

代わりにペアを使用できますか? Pairには引数をそれぞれの型に別々に転送するコンストラクタがあります。別の一般的な解決方法は、mutexへの一意のポインタを使用して作業することです。 –

+1

私はわかりませんが、 'MyClass'がデフォルトコンストラクタブルであれば' std :: make_shared >() 'に問題があるとは思わないでしょう。 – vu1p3n0x

+0

@ vu1p3n0x、それはデフォルトで構成可能ではありません。 – Velkan

答えて

1

2つの引数の簡単な解は、std::pairstd::piecewise_constructです。

std::tupleがありません。私はそれが欠陥だと考えます。

tuple(2つ以上の引数)が必要な場合は、「できます」という制限された値に対して、恐ろしいコードで行うことができます。

template<class T> 
struct placement_shared_helper { 
    std::aligned_storage_t<sizeof(T),alignof(T)> data; 
    T* get() { return reinterpret_cast<T*>(&data); } 
    template<class F> 
    void construct(F&& f) { 
    std::forward<F>(f)((void*)&data); 
    } 
    // dangerous if construct throws: 
    ~placement_shared_helper(){ get()->~T(); } 
}; 

template<class T, class F> 
std::shared_ptr<T> make_placement_shared(F&& f) { 
    auto r1 = std::make_shared<placement_shared_helper<T>>(); 
    r1->construct(std::forward<F>(f)); 
    return {r1->get(), r1}; // aliasing constructor 
} 

これはあなたが十分なサイズとアライメントのvoid*を渡され、関数オブジェクトを渡す必要があり、ストレージへの尖ったであなたのタイプを構築します。

placement_shared_helperの例外安全性を向上させることはできますが、それはうまく機能しており、私は怠惰です。構造体とstd::terminateから例外をキャッチすることを検討してください。

次の部分については、私たちは不正行為をします。初期化されていないメモリを取ってタプルがそのオブジェクトを格納するオフセットを得るためにタプルとして解釈するので、これは標準に違反します。悪いプログラマ。

template<class Dest, std::size_t...Is, class...Args> 
void placement_construct(std::index_sequence<Is...>, Dest* here, std::tuple<Args...> args) { 
    new((void*)here) Dest(std::get<Is>(args)...); 
} 
template<class Dest, class...Args> 
void placement_construct(Dest* here, std::tuple<Args...> args) { 
    return placement_construct(std::index_sequence_for<Args...>{}, here, std::move(args)); 
} 

template<class Dest, std::size_t...Is, class...Tuples> 
void placement_construct_tuple(std::index_sequence<Is...>, void* here, Tuples... tuples) { 
    using discard=int[]; 
    (void)discard{0,(void(
     placement_construct(&std::get<Is>(*(Dest*)here), std::move(tuples)) 
),0)...}; 
} 

template<class Dest, class...Tuples> 
void placement_construct_tuple(void* here, Tuples... tuples) { 
    placement_construct_tuple<Dest>(std::index_sequence_for<Tuples...>{}, here, std::move(tuples)...); 
} 

これは、タプルが特定の場所に構築されたオブジェクトの束であることを前提としています。我々はタプル型のメモリブロックを取り、各要素を順に構築します。例外がスローされた場合、悪いことが起こります。 catch終了しようと思っています。

make_placement_sharedは、void*を受け取り、オブジェクトを構成する関数をとります。

placement_construct_tupleはタプルのセットを取り、これを使用してタプル内のオブジェクトを順番に構築します。

auto r = make_placement_shared<std::tuple<MyClass, std::mutex>>(
    [&](void* here) { 
    placement_construct_tuple<std::tuple<MyClass, std::mutex>>(here, 
     std::forward_as_tuple(args_to_construct_MyClass_go_here), 
     std::make_tuple() // no args for mutex 
    ); 
    } 
); 

と定義されていない動作が終了しました。

+0

あなたの人生に依存している場合は、このコードを使用しますか? –

+0

@ MaximEgorushkinいいえ、コンパイルされていないテンプレートのメタプログラミングコードを心拍数モニタにインストールしないで、それを私の胸にインストールしませんか?それはばかげているだろう。私はおそらく、 'std :: tuple 、std :: mutex>'を作成し、上記を試してみるのではなく、参加しているブールのバイトを食べます。中期的には、私はタプルのための 'piecewise_convert' ctorが上記のハックを表示して消滅させるかもしれないと思います。 – Yakk

関連する問題