頻繁需要打印 `vector
#include
#include
#include
#include
template
void PrintContainer(const Container& c) // 引用避免拷貝
{
for (const auto& elem : c) // const 引用避免元素拷貝
std::cout << elem << ' ';
std::cout << '\n';
}
// 用法
int main() {
std::vector v = {1, 2, 3};
std::list l = {"a", "b", "c"};
std::deque d = {1.1, 2.2};
PrintContainer(v);
PrintContainer(l);
PrintContainer(d);
}
優點:支持所有滿足範圍-based for 要求的類型(含陣列、初始化列表、自定義容器);編譯期單態化,零運行時開銷;語義清晰。
#include
#include
#include
int main() {
std::list lst = {1, 3, 5, 4, 9, 6, 3};
std::copy(lst.cbegin(), lst.cend(),
std::ostream_iterator(std::cout, " "));
std::cout << '\n';
}
優點:純算法組合,無顯式循環,表達「複製到輸出流」意圖;可直接用於插入迭代器場景。
缺點:編譯錯誤信息晦澀;無法自定義分隔符邏輯(如最後無分隔符)。
#include
#include
#include
int main() {
std::list lst = {1, 3, 5, 4, 9, 6, 3};
using namespace boost::lambda;
std::for_each(lst.cbegin(), lst.cend(), std::cout << _1 << ' ');
std::cout << '\n';
}
現狀:C++11 Lambda 完美替代,**新代碼禁用**。
#include
#include
#include
int main() {
std::list lst = {1, 3, 5, 4, 9, 6, 3};
bool first = true;
std::for_each(lst.cbegin(), lst.cend(), [&first](int i) {
if (!first) std::cout << ", ";
first = false;
std::cout << i;
});
std::cout << '\n';
}
優點:可實現複雜格式化(如 JSON 風格 `[1, 2, 3]`、首尾無分隔符)。
缺點:樣板代碼較多。
// C++23 提案 / libfmt / {fmt} 庫當前可用
#include // 或 #include (C++23)
int main() {
std::vector v = {1, 2, 3};
std::cout << fmt::format("{}", v) << '\n'; // 輸出: [1, 2, 3]
std::cout << fmt::format("{:n}", v) << '\n'; // 輸出: 1, 2, 3 (無括號)
}
#include
#include
#include
#include
// 檢測是否為類字符串類型(避免逐字符打印 string)
template
struct is_string_like : std::false_type {};
template <> struct is_string_like : std::true_type {};
template <> struct is_string_like : std::true_type {};
template struct is_string_like : std::true_type {};
template struct is_string_like : std::true_type {};
namespace detail {
// 非字符串容器:逐元素打印
template
struct Printer {
static void print(const Container& c, std::ostream& os, std::string_view sep) {
bool first = true;
for (const auto& elem : c) {
if (!first) os << sep;
first = false;
os << elem;
}
}
};
// 字符串容器:整體打印(或特殊處理)
template
struct Printer::value>> {
static void print(const String& s, std::ostream& os, std::string_view) {
os << s;
}
};
}
// 統一入口
template
void PrintContainerEx(const Container& c, std::ostream& os = std::cout, std::string_view sep = " ") {
detail::Printer::print(c, os, sep);
os << '\n';
}
| 方案 | 運行時開銷 | 編譯期開銷 | 二進制膨脹 | 適用場景 |
|---|---|---|---|---|
| 模板範圍-for | 極低(內聯優化) | 低 | 每種容器類型一份代碼 | 通用首選 |
| copy + ostream_iterator | 低(迭代器適配器) | 中 | 類似 | 函數式風格偏好 |
| Lambda for_each | 低(捕獲變量) | 中 | 每個 Lambda 一份 | 複雜格式化需求 |
| fmt::format | 中(格式化解析) | 高(模板重) | 較大 | 生產級日誌/序列化 |
最佳實踐總結: 日常開發用**方案一(模板範圍-for)**,覆蓋 95% 場景;需複雜格式用**方案四(Lambda)**;生產級日誌/序列化引入 **{fmt} 庫(方案五)**;避免 Boost.Lambda、避免手寫針對特定類型的重載函數。