3

以下のコードには、「ユニバーサル参照」を受け入れる関数があります ( F&&)。F&&関数には、コンストラクターでのオブジェクトを受け入れる内部クラスもあります。F&&その時点でまだ普遍的な参照ですか?つまり、Fまだ推定型と見なされますか?

つまり、コンストラクターの初期化リストでstd::forward<F>orを使用する必要がありますか?std::move

#include "tbb/task.h"
#include <iostream>
#include <future>

template<class F>
auto Async(F&& f) -> std::future<decltype(f())>
{
    typedef decltype(f()) result_type;

    struct Task : tbb::task
    {
        Task(F&& f) : f_(std::forward<F>(f)) {} // is forward correct here?

        virtual tbb::task* execute()
        {
            f_();
            return nullptr;
        }

        std::packaged_task<result_type()> f_;
    };

    auto task = new (tbb::task::allocate_root()) Task(std::forward<F>(f));
    tbb::task::enqueue(*task);
    return task->f_.get_future();
}


int main()
{
    Async([]{ std::cout << "Hi" << std::endl; }).get();
}

ライブデモ。

4

2 に答える 2

6

F&&その時点でまだ普遍的な参照ですか?つまり、Fまだ推定型と見なされますか?

この種の混乱が、私が普遍的な参照という用語を嫌う理由です...そんなものはありません

私は、左辺値参照と右辺値参照、および参照の折りたたみとテンプレート引数推定の規則の観点からコードを理解することを好みます。

型の左辺値で関数が呼び出されるとL、引数Fは と推定されL&、参照折りたたみルールにより、F&&ちょうどL&です。コンストラクターでは何もTask変更されないため、コンストラクターは に渡された左辺値にバインドされている左辺値参照を取得するため、それを移動したくなく、値カテゴリを保持し、左辺値を左辺値。(左辺値からの移動は、左辺値が静かに移動されることを期待していなかった の呼び出し元を驚かせるでしょう。)F&&L&AsyncforwardAsync

型の右辺値で関数が呼び出されるとR、引数Fは と推定さRF&&ますR&&。コンストラクターではTask何も変更されませんが、コンストラクターは に渡された右辺値にバインドされている右辺値参照を取得するため、それを移動することもできますが、値カテゴリを保持し、右辺値を右辺値として転送するため、これも適切です。F&&R&&Asyncforward

先週の CppCon で、Herb Sutter は、"ユニバーサル リファレンス" の優先用語が転送リファレンスになったことを発表しました。

于 2014-09-18T10:10:53.673 に答える
1

ctor普遍的な参照ではなく、ボグ標準の右辺値参照または左辺値参照です。あなたの構造の問題は、それがミラーリングされているだけで、Asyncどちらが正しいかわからないことです(これで十分かもしれません)。

普遍的な参照になるためには、その call に対して型を推定する必要があり、多少関連する呼び出しの前に型を推定する必要はありません。

std::forward外部関数の引数は、保存された移動/コピーセマンティクスを使用して作成されたオブジェクトに実際に渡される必要があるため、私はまだ適切です。

于 2014-09-18T09:44:56.463 に答える