<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 可變參數模板(Variadic Templates) 要解決的問題: * 怎么創建一個擁有1個、2個或者更多的初始化器的類? * 怎么避免創建一個實例而只拷貝部分的結果? * 怎么創建一個元組? 最后的問題是關鍵所在:考慮一下元組!如果你能創建并且訪問一般的元組,那么剩下的問題也將迎刃而解。 這里有一個例子(摘自“可變參數模板簡述(A brief introduction to Variadic templates)”(參見參考)),要構建一個廣義的、類型安全的printf()。這個方法比用boost::format好的多,但是考慮一下: ``` const string pi = “pi”; const char* m = “The value of %s is about %g (unless you live in %s).n”; printf(m, pi, 3.14159, “Indiana”); ``` 這是除了格式字符串之外,沒有其它參數的情況下調用printf()的一個最簡單的例子了,所以我們將要首先解決: ``` void printf(const char* s) { while (s && *s) { if (*s==’%’ && *++s!=’%') //保證沒有更多的參數了 //%%(轉義字符,在格式字符串中代表% throw runtime_error(“格式非法: 缺少參數”); std::cout << *s++<<endl; } } ``` 這個處理好之后,我們必須處理有更多參數的printf(): ``` template<typename T, typename... Args> // 注意這里的"..." void printf(const char* s, T value, Args... args) // 注意"..." { while (s && *s) { //一個格式標記(避免格式控制符) if (*s=='%' && *++s!='%') { std::cout << value; return printf(++s, args...);//使用第一個非格式參數 } std::cout << *s++; } throw std::runtime error("extra args provided to printf"); } ``` 這段代碼簡單地“去除”了開頭的無格式參數,之后遞歸地調用自己。當沒有更多的無格式參數的時候,它調用第一個(很簡單)printf()(如上所示)。這也是標準的函數式編程在編譯的時候做的(?)。注意,`<<`的重載代替了在格式控制符當中(可能會有錯誤)的花哨的技巧。(譯注:我想這里可能指的是使用重載的`<<`輸出操作符,就可以避免使用各種技巧復雜的格式控制字符串。) Args…定義的是一個叫做“參數包”的東西。這個“參數包”僅僅是一個(有各種類型的值的)隊列,而且這個隊列中的參數可以從頭開始進行剝離(處理)。如果我們使用一個參數調用printf(),函數的第一個定義(printf(const char*))就被調用。如果我們使用兩個或者更多的參數調用printf(),那么函數的第二個定義(printf(const char*, T value, Args… args))就會被調用,把第一個參數當作字符串,第二個參數當作值,而剩余的參數都打包到參數包args中,用做函數內部的使用。在下面的調用中: ``` printf(++s, args…); ``` 參數包args被打開,所以參數包中的下一個參數被選擇作為值。這個過程會持續進行,直到args為空(所以第一個printf()最終會被調用)。 如果你對函數式編程很熟悉的話,你可能會發現這個語法和標準技術有一點不一樣。如果發現了,這里有一些小的技術示例可能會幫助你理解。首先我們可以聲明一個普通的可變參數函數模板(就像上面的printf()): ``` template<class ... Types> // 可變參數模板函數 //(補充:一個函數可以接受若干個類型的若干個參數) void f(Types ... args); f(); // OK: args不包含任何參數 f(1); // OK: args有一個參數: int f(2, 1.0); // OK: args有兩個參數: int和double ``` 我們可以建立一個具有可變參數的元組類型: ``` template<typename Head, typename... Tail> //這里是一個遞歸 //一個元組最基本要存儲它的head(第一個(類型/值))對 //并且派生自它的tail(剩余的(類型/值))對 //注意,這里的類型被編碼,而不是按一個數據來存儲 class tuple<Head, Tail...> : private tuple<Tail...> { typedef tuple<Tail...> inherited; public: tuple() { } // 默認的空tuple //從分離的參數中創建元組 tuple(typename add_const_reference<Head>::type v, typename add_const_reference<Tail>::type... vtail) : m_head(v), inherited(vtail...) { } // 從另外一個tuple創建tuple: template<typename... VValues> tuple(const tuple<VValues...>& other) : m_head(other.head()), inherited(other.tail()) { } template<typename... VValues> tuple& operator=(const tuple<VValues...>& other) // 等于操作 { m_head = other.head(); tail() = other.tail(); return *this; } typename add_reference<Head>::type head() { return m_head; } typename add_reference<const Head>::type head() const { return m_head; } inherited& tail() { return *this; } const inherited& tail() const { return *this; } protected: Head m_head; } ``` 有了定義之后,我們可以創建元組(并且復制和操作它們): ``` tuple<string,vector,double> tt("hello",{1,2,3,4},1.2); string h = tt.head(); // "hello" tuple<vector<int>,double> t2 = tt.tail(); ``` 要實現所有的數據類型可能會比較乏味,所以我們經常減少參數的類型,例如,可以使用標準庫中的make_tuple()函數: ``` template<class... Types> // 這個定義十分簡單(參見標準20.5.2.2) tuple<Types...> make_tuple(Types&&... t) { return tuple<Types...>(t...); } string s = "Hello"; vector<int> v = {1,22,3,4,5}; auto x = make_tuple(s,v,1.2); ``` 參考: * Standard 14.6.3 Variadic templates * [N2151==07-0011] D. Gregor, J. Jarvi: [Variadic Templates for the C++0x Standard Library](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2151.pdf). * [N2080==06-0150] D. Gregor, J. Jarvi, G. Powell: [Variadic Templates (Revision 3)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2080.pdf). * [N2087==06-0157] Douglas Gregor: [A Brief Introduction to Variadic Templates](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdf). * [N2772==08-0282] L. Joly, R. Klarer: [Variadic functions: Variadic templates or initializer lists? — Revision 1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2772.pdf). * [N2551==08-0061] Sylvain Pion: [A variadic std::min(T, …) for the C++ Standard Library (Revision 2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2551.pdf) . * Anthony Williams: [An introduction to Variadic Templates in C++0x](http://www.devx.com/cplus/Article/41533). DevX.com, May 2009.
                  <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>

                              哎呀哎呀视频在线观看