C++ fmt庫的使用小結(jié)
fmt 庫的核心優(yōu)勢是 用法簡潔、類型安全、兼容多場景,以下是從基礎(chǔ)到進(jìn)階的完整使用指南,涵蓋常用功能和關(guān)鍵場景。
一、前置準(zhǔn)備:環(huán)境配置
使用前需確保 fmt 庫已集成到項目中
- 編譯依賴:鏈接 fmt 庫(CMake 項目直接鏈接
fmt::fmt目標(biāo),非 CMake 項目需手動添加頭文件和src/format.cc編譯)。 - 頭文件引入:核心功能只需包含主頭文件:
#include <fmt/format.h> // 核心格式化功能(fmt::format、fmt::print 等) #include <fmt/ranges.h> // 容器格式化(可選,如 vector、map) #include <fmt/chrono.h> // 時間格式化(可選,如 std::chrono)
二、核心用法:格式化輸出與字符串構(gòu)建
fmt 的核心 API 是 fmt::format(構(gòu)建字符串)和 fmt::print(直接輸出),語法兼容 Python 格式化風(fēng)格,比 printf 更簡潔,比 iostreams 更高效。
1. 基礎(chǔ)格式化(類似 printf,但更安全)
支持位置參數(shù)、類型自動推導(dǎo),無需手動指定格式符(如 %d %s),錯誤會在編譯時捕獲。
#include <fmt/format.h>
#include <iostream>
int main() {
// 1. 基礎(chǔ)類型格式化(int、string、float 等)
std::string msg1 = fmt::format("整數(shù):{},字符串:{},浮點數(shù):{:.2f}", 42, "hello", 3.1415);
std::cout << msg1 << std::endl; // 輸出:整數(shù):42,字符串:hello,浮點數(shù):3.14
// 2. 位置指定(解決參數(shù)順序問題)
std::string msg2 = fmt::format("第2個參數(shù):{1},第1個參數(shù):{0}", "A", "B");
std::cout << msg2 << std::endl; // 輸出:第2個參數(shù):B,第1個參數(shù):A
// 3. 直接輸出到控制臺(無需手動拼接 cout)
fmt::print("直接輸出:{} + {} = {}\n", 10, 20, 30); // 輸出:直接輸出:10 + 20 = 30
// 4. 輸出到文件(支持 FILE* 或 std::ostream)
fmt::print(stdout, "輸出到標(biāo)準(zhǔn)輸出\n");
fmt::print(stderr, "輸出到標(biāo)準(zhǔn)錯誤\n");
return 0;
}
2. 容器格式化(開箱即用,無需手動遍歷)
包含 <fmt/ranges.h> 后,支持 std::vector、std::array、std::map 等容器直接格式化,默認(rèn)輸出類似 JSON 風(fēng)格。
#include <fmt/ranges.h>
#include <vector>
#include <map>
int main() {
std::vector<int> nums = {1, 2, 3, 4};
fmt::print("向量:{}\n", nums); // 輸出:向量:[1, 2, 3, 4]
std::map<std::string, int> score = {{"Alice", 95}, {"Bob", 88}};
fmt::print("字典:{}\n", score); // 輸出:字典:{"Alice": 95, "Bob": 88}
// 自定義分隔符(通過格式說明符)
fmt::print("向量(空格分隔):{:v}\n", fmt::join(nums, " ")); // 輸出:1 2 3 4
return 0;
}
3. 時間格式化(兼容 std::chrono)
包含 <fmt/chrono.h> 后,支持時間點、時間段的格式化,無需手動轉(zhuǎn)換 time_t。
#include <fmt/chrono.h>
#include <chrono>
int main() {
// 格式化當(dāng)前時間(本地時間)
auto now = std::chrono::system_clock::now();
fmt::print("當(dāng)前時間:{:%Y-%m-%d %H:%M:%S}\n", now); // 輸出:當(dāng)前時間:2024-10-01 14:30:00
// 格式化時間段
std::chrono::duration<double> diff = 2.5h + 30min;
fmt::print("時長:{}\n", diff); // 輸出:時長:2h30m0s
fmt::print("時長(秒):{:.1f}s\n", diff); // 輸出:時長(秒):9000.0s
return 0;
}
三、進(jìn)階用法:自定義類型與高級特性
1. 自定義類型格式化(可擴(kuò)展性核心)
通過實現(xiàn) fmt::formatter 模板特化,讓自定義類支持 fmt 格式化,還能兼容編譯時檢查。
#include <fmt/format.h>
// 自定義類
struct Point {
int x, y;
};
// 為 Point 實現(xiàn) formatter 特化
template <>
struct fmt::formatter<Point> {
// 解析格式說明符(可選,如 {:x} 控制輸出格式)
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.end(); // 此處不處理自定義格式符,直接返回結(jié)束迭代器
}
// 格式化邏輯
template <typename FormatContext>
auto format(const Point& p, FormatContext& ctx) -> decltype(ctx.out()) {
// 拼接輸出:(x, y)
return fmt::format_to(ctx.out(), "({}, {})", p.x, p.y);
}
};
int main() {
Point p = {10, 20};
fmt::print("坐標(biāo):{}\n", p); // 輸出:坐標(biāo):(10, 20)
return 0;
}
2. 避免緩沖區(qū)溢出:安全寫入
fmt::format_to_n 可限制輸出長度,防止緩沖區(qū)溢出,返回實際寫入的字符數(shù)和是否截斷的標(biāo)記。
#include <fmt/format.h>
#include <array>
int main() {
std::array<char, 10> buf; // 固定大小緩沖區(qū)(最多存 9 個字符 + 終止符)
auto [size, truncated] = fmt::format_to_n(buf.data(), buf.size() - 1, "Hello {}", "World");
buf[size] = '\0'; // 手動添加字符串終止符
fmt::print("結(jié)果:{},是否截斷:{}\n", buf.data(), truncated); // 輸出:結(jié)果:Hello W,是否截斷:true
return 0;
}
3. 動態(tài)參數(shù)(運行時確定參數(shù)個數(shù))
當(dāng)參數(shù)個數(shù)不確定時,使用 fmt::dynamic_format_arg_store 動態(tài)添加參數(shù),適合日志、配置等場景。
#include <fmt/format.h>
#include <vector>
int main() {
fmt::dynamic_format_arg_store<fmt::format_context> args;
args.push_back("name");
args.push_back("Alice");
args.push_back("age");
args.push_back(25);
// 動態(tài)參數(shù)格式化
std::string msg = fmt::vformat("{}: {}, {}: {}", args);
fmt::print("{}\n", msg); // 輸出:name: Alice, age: 25
return 0;
}
四、特殊場景:與 C 標(biāo)準(zhǔn)庫 / STL 兼容
1. 兼容 printf 格式符
如果習(xí)慣 printf 的格式符(如 %04d %x),fmt 完全支持,同時保留類型安全。
#include <fmt/format.h>
int main() {
// 用 printf 格式符格式化
fmt::print("十六進(jìn)制:{:x}\n", 255); // 輸出:ff
fmt::print("補(bǔ)零對齊:{:04d}\n", 42); // 輸出:0042
fmt::print("科學(xué)計數(shù)法:{:e}\n", 123.4); // 輸出:1.234000e+02
return 0;
}
2. 格式化 STL 字符串與流
支持 std::string、std::wstring,也可輸出到 std::ostream(如 std::cout)。
#include <fmt/format.h>
#include <string>
#include <iostream>
int main() {
std::string name = "Bob";
// 格式化 std::string
std::string msg = fmt::format("Hello, {}", name);
std::cout << msg << std::endl; // 輸出:Hello, Bob
// 直接輸出到 std::ostream
fmt::print(std::cout, "Width: {}\n", 100); // 等價于 std::cout << "Width: 100" << std::endl
return 0;
}
五、常見問題與注意事項
- 編譯錯誤:若使用容器 / 時間格式化時報錯,檢查是否包含對應(yīng)的頭文件(
<fmt/ranges.h><fmt/chrono.h>)。 - C++ 版本要求:核心功能支持 C++11 及以上,部分高級特性(如編譯時格式檢查)需 C++17+。
- 性能優(yōu)化:頻繁格式化場景可使用
fmt::memory_buffer復(fù)用緩沖區(qū),減少內(nèi)存分配:fmt::memory_buffer buf; fmt::format_to(buf, "First: {}", 1); fmt::format_to(buf, ", Second: {}", 2); std::string result = fmt::to_string(buf); // 結(jié)果:"First: 1, Second: 2"
總結(jié)
fmt 庫的使用核心是 “簡潔 + 安全”:基礎(chǔ)場景用 fmt::format/fmt::print 替代 printf/iostreams,進(jìn)階場景(自定義類型、動態(tài)參數(shù))通過擴(kuò)展 formatter 或 dynamic_format_arg_store 實現(xiàn),同時保持高性能和跨平臺兼容性。
到此這篇關(guān)于C++ fmt庫的使用小結(jié)的文章就介紹到這了,更多相關(guān)C++ fmt庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
C++高性能服務(wù)器框架之協(xié)程調(diào)度模塊
從零實現(xiàn)一個 C++ 輕量級日志系統(tǒng)原理與實踐指南
C語言數(shù)據(jù)結(jié)構(gòu)實例講解單鏈表的實現(xiàn)

