<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                #Item 24: Distinguish universal references from rvalue references. 大多數人說真相可以讓我們感到自由,但是在某些情況下,一個巧妙的謊言也可以讓人覺得非常輕松。這個Item就是要編制一個“謊言”。因為我們是在和軟件打交道。所以我們避開“謊言”這個詞:我們是在編制一種“抽象”的意境。 為了聲明一個類型T的右值引用,你寫下了T&&。下面的假設看起來合理:你在代碼中看到了一個"T&&"時,你看到的就是一個右值引用。但是,它可沒有想象中那么簡單: ```cpp void f(Widget&& param); //rvalue reference Widget&& var1 = Widget(); //rvalue reference auto&& var2 = var1; //not rvalue reference template<typename T> void f(std::vector<T>&& param) //rvalue reference template<typename T> void f(T&& param); //not rvalue reference ``` 實際上,“T&&”有兩個不同的意思。首先,當然是作為rvalue reference,這樣的引用表現起來和你預期一致:只和rvalue做綁定,它們存在的意義就是表示出可以從中move from的對象。 “T&&”的另外一個含義是:既可以是rvalue reference也可以是lvalue reference。這樣的references在代碼中看起來像是rvalue reference(即"T&&"),但是它們_也_可以表現得就像他們是lvalue refernces(即"T&")那樣.它們的dual nature允許他們既可以綁定在rvalues(like rvalue references)也可以綁定在lvalues(like lvalue references)上。進一步來說,它們可以綁定到const或者non-const,volatile或者non-volatile,甚至是const + volatile對象上面。它們幾乎可以綁定到任何東西上面。為了對得起它的全能,我決定給它們起個名字:universal reference.(Item25將會解釋universal references總是可以將std::forward應用在它們之上,本書出版之時,C++委員會的一些人開始將universal references稱之為forward references). 兩種上下文中會出現universal references。最普通的一種是function template parameters,就像上面的代碼所描述的例子那樣: ```cpp template<typename T> void f(T&& param); //param is a universal reference ``` 第二種context就是auto的聲明方式,如下所示: ```cpp auto&& var2 = var1; //var2 is a universal reference ``` 這兩種context的共同點是:都有type deduction的存在。在template fucntion f中,參數param的類型是被deduce出來的,在var2的聲明中,var2的類型也是被deduce出來的。和接下來的例子(也可以和上面的栗子一塊兒比)對比我們會發現,下面栗子是不存在type deduction的。如果你看到"T&&",卻沒有看到type deduction.那么你看到的就是一個rvalue reference: ```cpp void f(Widget&& param); //no type deduction //param is an rvalue reference Widget&& var1 = Widget(); //no type deduction //var1 is an rvalue reference ``` 因為universal references是references,所以它們必須被初始化。universal reference的initializer決定了它表達的是rvalue reference或者lvalue reference。如果initializer是rvalue,那么universal reference對應的是rvalue reference.如果initializer是lvalue,那么universal reference對應的就是lvalue reference.對于身為函數參數的universal reference,initializer在call site(調用處)被提供: ```cpp template<typename T> void f(T&& param); //param is a universal reference Widget w; f(w); //lvalue passed to f;param's type is Widget&(i.e., an lvalue reference) f(std::move(w)); //rvalue passed to f;param's type is Widget&&(i.e., an rvalue reference) ``` 對universal的reference來說,type deduction是必須的,但還是不夠,它要求的格式也很嚴格,必須是"T&&".再看下我們之前寫過的栗子: ```cpp template<typename T> void f(std::vector<T>&& param); //param is an rvalue reference ``` 當f被調用時,類型T會被deduce(除非調用者顯式的指明類型,這種邊緣情況我們不予考慮)。param聲明的格式不是T&&,而是std::vector<T>&&.這就說明它不是universal reference,而是一個rvalue reference.如果你傳一個lvalue給f,那么編譯器肯定就不高興了。 ```cpp std::vector<int> v; f(v); //error! can't bind lvalue to rvalue reference ``` 即使一個最簡單前綴const.也可以把一個reference成為universal reference的可能抹殺: ```cpp template<typename T> void f(const T&& param); //param is an rvalue reference ``` 如果你在一個template里面,并且看到了T&&這樣的格式,你可能就會假設它就是一個universal reference.但是并非如此,因為還差一個必要的條件:type deduction.在template里面可不保證一定有type deduction.看個例子,std::vector里面的push_back方法。 ```cpp template<class T, class Allocator = allocator<T>> class vector{ public: void push_back(T&& x); ... } ``` 以上便是只有T&&格式卻沒有type deduction的例子,push_back的存在依賴于一個被instantiation的vector.用于instantiation的type就完全決定了push_back的函數聲明。也就是說 ```cpp std::vector<Widget> v; ``` 使得std::vector的template被instantiated成為如下格式: ```cpp class vector<Widget, allocator<Widget>>{ public: void push_back(Widget&& x); //rvalue reference ... }; ``` 如你所見,push_back沒有用到type deduction.所以這個vector<T>的$push_back$(有兩個overload的$push_back$)所接受的參數類型是rvalue-reference-to-T. 與之相反,std::vector中概念上相近的$emplace_back$函數確實用到了type deduction: ```cpp template<class T,class Allocator=allocator<T>> class vector{ public: template <class... Args> void emplace_back(Args&&... args); ... }; ``` type parameter```Args```獨立于vector的type parameter ```T```,所以每次調用```emplace_back```的時候,```Args```就要被deduce一次。(實際上,```Args```是一個parameter pack.并不是type parameter.但是為了討論的方便,我們姑且稱之為type parameter)。 我之前說universal reference的格式必須是```T&&```, 事實上,emplace_back的type parameter名字命名為Args,但這不影響args是一個universal reference,管它叫做T還是叫做Args呢,沒啥區別。舉個例子,下面的template接受的參數就是universal reference.一是因為格式是"type&&",二是因為param的type會被deduce(再一次提一下,除非caller顯示的指明了type這種邊角情況). ```cpp template<typename MyTemplateType> //param is a void someFunc(MyTemplateType&& param); //universal reference ``` 我之前提到過auto變量可以是universal references.更準確的說,聲明為auto&&的變量就是universal references.因為類型推導發生并且它們也有正確的格式("T&&").auto類型的universal references并不想上面說的那種用來做function template parameters的universal references那么常見,在最近的C++ 11和C++ 14中,它們變得非常活躍。C++ 14中的lambda expression允許聲明auto&&的parameters.舉個栗子,如果你想寫一個C++ 14的lambda來記錄任意函數調用花費的時間,你可以這么寫: ```cpp auto timeFuncInvocation = [](auto&& func, auto&&... params) //C++ 14 { start timer; std::forward<decltype(func)>(func)( std::forward<decltype(params)>(params)... //invoke func on params ); stop timer and record elapsed time } ``` 如果你對于"std::forward<decltype(blah blah blah)"的代碼的反應是“這是什么鬼!?”,這只是意味著你還沒看過Item33,不要為此擔心。 func是一個可以綁定到任何callable object(lvaue或者rvalue)的universal reference.args是0個或多個universal references(即a universal reference parameter pack),它可以綁定到任意type,任意數量的objects.所以,多虧了auto universal reference,timeFuncInvocation可以記錄pretty much any的函數調用(any和pretty much any的區別,請看Item 30). 本Item中universal reference的基礎,其實是一個謊言,呃,或者說是一種"abstraction".隱藏的事實被稱之為_reference collapsing_,Item 28會講述。但是該事實并不會降低它的用途。rvalue references以及universal references會幫助你更準確第閱讀source code(“Does that T&& I’m looking at bind to rvalues only or to everything?”),和同事溝通時避免歧義(“I’m using a universal reference here, not an rvalue reference...”),它也會使得你理解Item 25和Item 26,這兩條都依賴于此區別。所以,接受理解這個abstraction吧。牛頓三大定律(abstraction)比愛因斯坦的相對論(truth)一樣有用且更容易應用,universal reference的概念也可以是你理解reference collapsing 的細節。 |要記住的東西| |:--------- | |如果一個函數的template parameter有著T&&的格式,且有一個deduce type T.或者一個對象被生命為auto&&,那么這個parameter或者object就是一個universal reference.| |如果type的聲明的格式不完全是type&&,或者type deduction沒有發生,那么type&&表示的是一個rvalue reference.| |universal reference如果被rvalue初始化,它就是rvalue reference.如果被lvalue初始化,他就是lvaue reference.|
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看