3

次のようなプッシュ関数を持つ同時キューのテンプレート化された実装があります。

template <typename T>
class concurrent_queue
{
public:

    // other code...

    void push(const T& item)
    {
        std::unique_lock<std::mutex> mlock(mutex);
        queue.push_back(std::forward(item));
        mlock.unlock();
        notEmpty.notify_one();
    }

private:

    std::deque<T>               queue;
    std::mutex                  mutex;
    // other stuff...
};

後で、インスタンス化して次のように使用します。

concurrent_queue<c2Type> m_queue;  // c2 type is some struct declared previously

次に、アイテムをキューにプッシュしようとすると、前述のコンパイラ エラーが発生します。

c2Type c2message;

// fill in the message struct...
m_queue.push(c2message);

std::functionオブジェクトを格納するスレッドプール実装の一部として、以前にキューを正常に使用しました。この場合、型を推測できない理由がわかりません。何かご意見は?

4

1 に答える 1

7

「左辺値」や「右辺値」などの値カテゴリは、式のプロパティです。変数に名前を付ける式は、型右辺値参照をsome_type持つ変数に名前を付ける場合でも、常に左辺値式です。

lvalue-reference と rvalue-references を使用して、さまざまなカテゴリの式をバインドします。慣例により、lvalue-references はlvalues にバインドされているものとして扱い、rvalue-references はrvalues にバインドされているものとして扱います。

std::forward参照が参照していると想定するものの値カテゴリを復元することを目的としています。例えば:

int   i = 42;
int&  l = i;
int&& r = 21;

l // this expression is an lvalue-expression
r // this expression is an lvalue-expression, too (!)

std::forward<int& >(l) // this function-call expression is an lvalue-expression
std::forward<int&&>(r) // this function-call expression is an rvalue-expression

std::forwardは「通常の関数」であるため、引数を使用するだけでは値カテゴリを復元できません。両方の引数は左辺値式です。テンプレート引数を手動で指定して、復元する値カテゴリを指定する必要があります。

これは、右辺値参照なのか左辺値参照なのかアプリオリにわからない参照がある場合にのみ意味があります。これは、転送参照を使用して完全転送を使用する関数を作成する場合に当てはまります。

ところで、値カテゴリを復元して、受け取った引数から別の関数を移動できるようにしたいと考えています。右辺値引数を受け取った場合は、右辺値を渡して、呼び出された関数を移動できるようにします。


OPのような機能の場合:

void push(const T& item)

itemへの型左辺値参照const Tがあることがわかっています。したがって、必要ありませんstd::forward:

void push(const T& item) {
    // ...
    queue.push_back(item); // pass the lvalue argument as an lvalue
    // ...
}

別のオーバーロードを追加すると:

void push(T&& item)

std::forwardそのパラメーターの型itemは常に右辺値参照T であるため、まだ必要ありません(参照型ではないと仮定しTます) :

void push(T&& item) {
    // ...
    queue.push_back(std::move(item)); // pass the rvalue argument as an rvalue
    // ...
}

次のようなものがある場合のみ

template<typename U>
void push(forwarding_reference<U> item)

whereforwarding_reference<U>左辺値参照または右辺値参照のいずれかである場合、次のものが必要ですstd::forward

template<typename U>
void push(forwarding_reference<U> item) // not C++, read on
{
    // ...
    queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
                                            // and rvalue arguments as rvalues
    // ...
}

実装の詳細により、上記を次のように記述する必要があります。

template<typename U>
void push(U&& item) {
    // ...
    queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
                                            // and rvalue arguments as rvalues
    // ...
}

上記U&& itemは右辺値参照ではなく、転送参照であることに注意してください。X転送参照を取得するには、いくつかのテンプレート型パラメーターとフォームの関数パラメーターを含む関数テンプレートが必要ですX&& x

于 2014-12-29T22:42:18.980 に答える