6
 template<typename T>
   class BlockingQueue
   { 
       std::queue<T> container_;

       template< typename U >
       void push(U&& value)
       {
           static_assert(std::is_same<T, typename std::remove_reference<U>::type>::value,"Can't call push without the same parameter as template parameter's class");

           container_.push(std::forward<U>(value)); 
       }
};

I would like BlockingQueue::push method be able to handle both rvalue and lvalue reference of object of type T to forward it to std::queue::push correct version. Is it preferable to do like the above code, or to provide two versions of push method inside my BlockingQueue class ? One for lvalue and one for rvalue

4

2 に答える 2

7

実装は私には正しいようで、仕事をしています。

それにもかかわらず、左辺値と右辺値に異なる実装を提供することは、あなたの場合には良い考えかもしれません. (私が考えることができる)主な理由は、テンプレート型引数の推定がbraced-init-listsでは機能しないことです。検討:

struct foo {
    foo(std::initializer_list<int>) {
    }
};

// ...
foo f{1, 2, 3};    // OK

BlockingQueue<foo> b;

OPのコード付き(*)

b.push(f);         // OK
b.push({1, 2, 3}); // Error

代わりに、次のオーバーロードBlockingQueue::pushが提供されます。

void push(const T& value) {
    container_.push(value); 
}

void push(T&& value) {
    container_.push(std::move(value)); 
}

そうすれば、以前は失敗していた行が正常に機能するようになります。

集計にも同じ引数が適用されます。たとえば、次のようfooに定義された場合

struct foo {
    int a, b, c;
};

上記と同じ動作が見られます。

私の結論は、BlockingQueueより多くの型 (集約またはstd::initializer_lists を取るコンストラクターを持つ型を含む) をサポートする場合は、2 つの異なるオーバーロードを提供する方がよいということです。

(*) OP のコードの小さな修正: でstatic_assert使用する必要がありますtypename

typename std::remove_reference<U>::type>::value
^^^^^^^^
于 2013-11-01T09:15:00.243 に答える
0

完全転送を使用する場合は、クラスemplaceのメソッドを使用することをお勧めします。メソッドは、指定された引数をコンストラクターに転送します。が と同じかどうかを確認する必要はありません。から構築可能である限り、コンパイルする必要があります。さらに、必要に応じて、可変個引数のテンプレート引数を使用できます。queueemplaceTTUTU

template<typename... Args>
void push(Args&&... args)
{
    container_.emplace(std::forward<Args>(args)...);
}

したがって、 T が指定された引数から構築可能である限り、好きなものをプッシュできます。

于 2013-11-01T12:13:30.037 に答える