2002 年 10 月 C++ 標準委員會會議通過兩大庫擴展提案,其中 Jaakko Järvi 的 tuple 型別(源自 Boost)徹底解決了「函式需要回傳多個值」的長期痛點。本文追隨 Herb Sutter 筆觸,從動機案例切入,展示 tuple 的強大表達力。
// 僅回傳商數
int IntegerDivide(int n, int d) { return n / d; }
// 需同時取得商數與餘數,傳統做法:
// 1. 輸出參數(語意不清)
int IntegerDivide(int n, int d, int& r) { r = n % d; return n / d; }
// 2. 雙輸出參數(對稱但冗長)
void IntegerDivide(int n, int d, int& q, int& r) { q = n / d; r = n % d; }
// 3. std::pair(僅限兩值,型別固定)
std::pair<int,int> IntegerDivide(int n, int d) {
return std::pair<int,int>(n/d, n%d);
}
#include <tuple> // C++11 標準庫,或 boost/tuple/tuple.hpp
// 回傳 tuple<int, int>
std::tuple<int,int> IntegerDivide(int n, int d) {
return std::tuple<int,int>(n/d, n%d);
}
// 使用 get<N>() 存取(編譯期索引)
auto result = IntegerDivide(5, 4);
std::cout << "quotient = " << result.get<0>() // 1
<< " remainder = " << result.get<1>(); // 1
// 浮點除法:商數、餘數、是否下溢
std::tuple<float, float, bool> FloatDivide(float n, float d) {
// 實作略...
return std::make_tuple(quotient, remainder, underflow);
}
// 若用 pair 需嵌套:pair<float, pair<float, bool>> —— 可讀性極差
tie 解包// C++17 結構化綁定(最推薦)
auto [q, r] = IntegerDivide(5, 4); // 直接宣告變數
// C++11/14 使用 std::tie
int quotient, remainder;
std::tie(quotient, remainder) = IntegerDivide(5, 4);
// 忽略特定值
std::tie(std::ignore, remainder) = IntegerDivide(5, 4); // 只要餘數
std::tuple<int,int> tr = IntegerDivide(5, 4);
std::cout << tr; // 輸出:(1 1)
// 自訂格式
std::cout << std::tuples::set_open('[')
<< std::tuples::set_close(')')
<< std::tuples::set_delimiter(',')
<< tr; // 輸出:[1,1]
| 特性 | std::pair | std::tuple | 自訂 struct |
|---|---|---|---|
| 元素數量 | 固定 2 | 任意 (0~實作上限) | 任意 |
| 元素存取 | .first/.second | .get<N>() / 結構化綁定 | 具名欄位 |
| 型別推導 | make_pair | make_tuple / 自動推導 | 需手寫 |
| 比較運算 | 內建字典序 | 內建字典序 | 需手寫 |
| 語意表達 | 隱含「雙元組」 | 通用「元組」 | 領域語意明確 |
std::apply、std::make_from_tuple 配合。map::value_type、minmax 結果)。Tuple 將「多重回傳值」從權宜之計昇華為第一級語言支援,配合 C++17 結構化綁定,已成現代 C++ 不可或缺的工具箱核心組件。