2017-08-08 17 views
4

私はhereのコードを見ました。説明は言う:&&、範囲ベースのループとテンポラリはどのように連携しますか?

我々はまた、自動& &を使用して、フォワーディング参照として取り込むことができます。つまり、 の自動& &は、左辺値の参照の場合は&、左の場合は& rvaludの参照の場合は自動的に解決されます。次に、テンポラリマップ上の 範囲ベースのforループからの出力をキャプチャする例を示します。

値が(ので、この場合には何の減衰はありません)左辺値であると称する場合、私はauto&auto&&の減衰を理解してください。私が苦労していることは、一時的な地図、ループに基づいた範囲と移動された値がどのように連動しているかを理解することです。これらのことがお互いにどのように機能するのか、そして反復されている一時的なものから移動するのはなぜ大丈夫なのか説明してください。

#include <iostream> 
#include <map> 

std::map<std::string, int> get_map() 
{ 
    return { 
     { "hello", 1 }, 
     { "world", 2 }, 
     { "it's", 3 }, 
     { "me", 4 }, 
    }; 
} 

int main() { 
    for (auto&& [ k, v ] : get_map()) 
     std::cout << "k=" << k << " v=" << v << '\n'; 
} 
+3

簡潔にするために、あなたはすでに[参照縮退](https://stackoverflow.com/questions/13725747/concise-explanation-of-reference-collapsing-rules-requested-1a-a-a-2)を理解しています。あれは正しいですか ? – WhozCraig

+0

fyi:ここでは動きません。関数内のRVOが返されます。 –

+0

@RichardCritten [C++ 1z]というタグが付けられているため、「潜在的なRVO」はありません。これは一時的なものであり、forループで必要となるまでは実現しません。 C++ 17より前では、実装定義されていましたが、ここでは必須であり、もはやRVOと全く同じものではありません。 –

答えて

1

つの可視この例でauto&&の二つの異なる用途、隠れ一方があります。したがって

{ 
    auto&& __range = get_map(); // the temporary get_map() is bound to a reference, which 
           // extends its lifetime to the lifetime of the reference 
           // decltype(__range) is std::map<std::string, int>&& 

    auto __begin = __range.begin(); 
    auto __end = __range.end();  // potential different type from __begin since C++17 
    for (; __begin != __end; ++__begin) { 
     auto&& __elem = *__begin; // this is your structured binding declaration 
            // *__begin is an lvalue, so decltype(__elem) is 
            // std::pair<std::string const, int> const& 


     // the actual destructuring here 
     std::string const& k = std::get<0>(__elem);  
     int const& v   = std::get<1>(__elem); 

     // now your body 
     std::cout << "k=" << k << " v=" << v << '\n'; 
    } 
} 

:最大限に冗長であるためには、あなたが持っているループがアウトに展開する

それが繰り返されていること、一時から移動しても大丈夫だ理由

このコードでは何も動いていません。 mapは、__rangeに組み込まれています。それはあなたが繰り返すものです。最後のブレースの範囲外になります。このこと


注:

値が呼ぶならば、私はauto&auto&&の減衰を理解して行うが、左辺値

では全く正しくありません。まず、「崩壊」とは呼ばれません。たとえば、配列を関数に渡したときに崩壊が起こり、ポインタに崩壊します。さらに、auto&&auto&に崩壊しません。初期化子が左辺値の場合、auto&&auto&は同じように動作します。イニシャライザがrvalueの場合、auto&はコンパイルに失敗しますが、auto&&が機能し(rvalue参照を生成します)。

+0

最後の部分もあまり正しくありません。あなたのイニシャライザが左辺値の場合、 'auto &&'は 'auto'を' auto 'として推論し、*は*参照崩壊を行います。[この投稿はScott Meyers氏](https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers)のすべての詳細を見ることができます。 –

関連する問題