web-dev-qa-db-ja.com

範囲ベースのforループで転送参照を使用する利点は何ですか?

読み取り専用操作を実行する場合は、const auto&で十分です。しかし、私はぶつかった

for (auto&& e : v)  // v is non-const

最近数回。これは私を不思議に思う:

auto&またはconst auto&と比較して、いくつかのあいまいなケースでは、転送参照を使用することでパフォーマンスが向上する可能性がありますか?

shared_ptrは、あいまいなコーナーケースの疑いがある)


更新お気に入りで見つけた2つの例:

基本型を反復処理するときにconst参照を使用することの短所はありますか
範囲ベースのforループを使用してマップの値を簡単に反復できますか?

質問に集中してください:なぜ範囲ベースのforループでauto &&を使用したいのですか?

108
Ali

私が見ることができる唯一の利点は、シーケンス反復子がプロキシ参照を返し、非参照方法でその参照を操作する必要がある場合です。たとえば、次のことを考慮してください。

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

iteratorから返される右辺値vector<bool>::referenceは非定数左辺値参照にバインドしないため、これはコンパイルされません。しかし、これは動作します:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

そうは言っても、このようなユースケースを満たす必要があると知らない限り、この方法でコーディングすることはしません。つまりこれはdoesするので、人々はあなたが何をしているのか疑問に思うので、これを無償で行いません。そして、私がそれをしたとしても、理由についてのコメントを含めても害はありません:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}

編集

私のこの最後のケースは、本当に理にかなったテンプレートであるべきです。ループが常にプロキシ参照を処理していることがわかっている場合、autoauto&&と同様に機能します。しかし、ループが非プロキシ参照を処理する場合とプロキシ参照を処理する場合は、auto&&が最適なソリューションになると思います。

85
Howard Hinnant

_auto&&_または niversal reference を範囲ベースのfor- loopと共に使用すると、取得したものをキャプチャできるという利点があります。ほとんどの種類のイテレータでは、おそらくT型に対して_T&_または_T const&_のいずれかを取得します。興味深いケースは、反復子の逆参照が一時的な結果をもたらす場合です。C++ 2011では要件が緩和され、反復子は必ずしも左辺値を生成する必要はありません。ユニバーサル参照の使用は、std::for_each()の引数転送と一致します。

_template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}
_

関数オブジェクトfは、_T&_、_T const&_、およびTを異なる方法で処理できます。範囲ベースのfor-ループの本体が異なるのはなぜですか?もちろん、ユニバーサル参照を使用して型を推定したことを実際に利用するには、それに応じてそれらを渡す必要があります。

_for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}
_

もちろん、std::forward()を使用することは、戻り値の移動を受け入れることを意味します。このようなオブジェクトが、私が知らないテンプレート以外のコードで意味をなすかどうか(まだ?)。ユニバーサルリファレンスを使用すると、コンパイラに正しい情報を提供するためのより多くの情報を提供できると想像できます。テンプレート化されたコードでは、オブジェクトで何が起こるべきかを決定することはありません。

25
Dietmar Kühl

私はほとんど常にauto&&を使用しています。必要がないのに、なぜEdgeのケースに噛まれるのですか?入力する方が短いので、単純にもっと...透明であることがわかります。 auto&& xを使用すると、毎回x*itであることがわかります。

7
Puppy