2014-12-02 77 views
5

前段時間,打印出std :: tuple的解決方案發布爲here。大多數情況下,我會得到所發生的事情。儘管我很難理解print_tuple函數中發生了什麼。漂亮的打印元組解析

template<class Ch, class Tr, class Tuple, std::size_t... Is> 
void print_tuple(std::basic_ostream<Ch,Tr>& os, Tuple const& t, seq<Is...>){ 
    using swallow = int[]; 
    (void)swallow{0, (void(os << (Is == 0? "" : ", ") << std::get<Is>(t)), 0)...}; 
} 

我不明白這個函數體內發生了什麼。據我所知,這與解包Is有關。我得知,條件Is == 0正在檢查以查看我們是否處於頭部元素。

那麼這是怎麼回事?

+5

該代碼從初始值設定項列表中構造(然後拋出)一個int []數組,其中每個元素爲0,但打印元組的一個元素作爲副作用(通過逗號運算符)。初始化程序列表的使用只是爲了進入包擴展工作的上下文。 – 2014-12-02 15:20:41

+0

啊!所以'swallow {...}'構造是int []的初始化列表。乍看之下我沒有明白。 – sguzman 2014-12-02 17:14:33

回答

9

讓我們通過一個例子用任意元組,說:

using Tuple = tuple<char, int, string>; 

因此,我們的功能將被用整數序列是:

seq<0, 1, 2> 

而我們在包擴展正文是:

(void)swallow{0, (void(os << (Is == 0? "" : ", ") << std::get<Is>(t)), 0)...}; 

其中,如果我們手動擴展它的編譯器的方式,將成爲:

(void)swallow{0, 
       (void(os << (0 == 0? "" : ", ") << std::get<0>(t)), 0), 
       (void(os << (1 == 0? "" : ", ") << std::get<1>(t)), 0), 
       (void(os << (2 == 0? "" : ", ") << std::get<2>(t)), 0) 
       }; 

然後評估的分支:

(void)swallow{0, 
       (void(os << "" << std::get<0>(t)), 0), 
       (void(os << ", " << std::get<1>(t)), 0), 
       (void(os << ", " << std::get<2>(t)), 0) 
       }; 

這就是說,我們正在建設的4 0秒的整數數組,印刷出來的元組的內容的副作用,用逗號分隔,確保我們不以逗號開頭。四個表達式必須按順序評估,以保證元組內容按順序打印。

最初的(void)強制轉換隻是爲了避免編譯器在打開所有警告時發出的未使用變量警告。初始的0在數組初始化中處理元組爲空的情況。

+0

我開始明白了。 void(...)'做什麼? – sguzman 2014-12-02 17:24:16

+1

@SalvadorGuzman將'os << whatever'的結果轉換爲'void',以便表達式'(void(stuff),0)'絕對返回'0'。這是因爲有人決定爲'operator,()'寫一個重載而不是返回int的重載。 – Barry 2014-12-02 17:33:01

+0

這更有意義。最後一個問題。那麼'...'運算符是一個解包器嗎?我可以依靠它來返回逗號分隔值嗎? – sguzman 2014-12-02 17:41:09

1

(os << (Is == 0? "" : ", ") << std::get<Is>(t))打印的Is個元素(前綴", "Is > 0

然後,結果鑄造void避免逗號操作的可能的過載。

(/*previous stuff*/, 0)...做了一系列的0

{0, /*previous stuff*/ }管理情況下sizeof...(Is) == 0

swallow /*previous stuff*/構建0 int數組。

void /*previous stuff*/:投射失效以避免警告。