La gestione della formattazione del testo è un aspetto fondamentale in qualsiasi progetto software, e in C++ spesso si riduce a una scelta tra compromessi. Da un lato, abbiamo le funzioni C-style come printf, che offrono velocità ma peccano in sicurezza e type-safety. Dall’altro, le classi iostream come stringstream garantiscono type-safety ma introducono overhead prestazionali e verbosità nel codice. Questa dicotomia ha portato a un problema persistente in molte codebase enterprise: codice lento, difficile da manutenere e potenzialmente vulnerabile a errori di formato.
Quando ho lavorato su un sistema di elaborazione dati ad alta frequenza che processava milioni di record al secondo, la necessità di un logging efficiente e chiaro era cruciale. Ogni millisecondo contava, e gli errori di formattazione potevano portare a log illeggibili o, peggio, a crash in produzione. È qui che fmtlib/fmt entra in gioco, offrendo una soluzione che unisce il meglio dei due mondi: la velocità di printf con la sicurezza e la flessibilità di una moderna libreria C++.
Testato su: Ubuntu 22.04 LTS · GCC 11.4 · fmtlib 10.1.1 · Settembre 2026
Prerequisiti / Ambiente di test
Per seguire questa guida, avrai bisogno di un ambiente di sviluppo C++ con un compilatore moderno (GCC 9+ o Clang 9+). fmt può essere integrato facilmente tramite sistemi di build come CMake o Vcpkg. Per i nostri scopi, useremo CMake.
Assicurati di avere CMake installato:
sudo apt update
sudo apt install build-essential cmake
1. Introduzione a fmtlib/fmt
fmt è una libreria open-source per la formattazione di testo in C++. È stata progettata per essere una soluzione moderna, veloce e sicura, e la sua influenza è tale che è stata adottata come base per la libreria standard C++20 . Offre una sintassi simile a quella usata in Python (f-strings) o Rust, permettendo di creare stringhe formattate in modo intuitivo e leggibile.
Perché scegliere fmt rispetto a printf e iostream?
- Sicurezza Type-Safe: A differenza di
printf,fmtverifica i tipi degli argomenti in fase di compilazione, prevenendo errori comuni come il mismatch tra specificatori di formato e tipi di dati. - Performance:
fmtè significativamente più veloce diiostreame, in molti scenari, anche diprintf, grazie a ottimizzazioni interne e all’evitamento di overhead non necessari. Questo è cruciale in applicazioni che richiedono alta throughput, come sistemi di logging o elaborazione dati. - Sintassi Intuitiva: La sintassi
{}per i placeholder è molto più chiara e meno soggetta a errori rispetto agli specificatori di formato diprintf(%d,%s, ecc.). - Estensibilità: Permette di definire formattatori personalizzati per tipi definiti dall’utente, rendendola estremamente flessibile per strutture dati complesse. Leggi anche: Come serializzare oggetti C++ in JSON per il logging
2. Installazione e Uso Base di fmt
Il modo più semplice per integrare fmt in un progetto C++ è tramite CMake. Creiamo un semplice progetto.
Crea una directory per il progetto:
mkdir fmt_example
cd fmt_example
Crea un file CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(FmtExample CXX)
find_package(fmt CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE fmt::fmt)
Crea il file main.cpp:
#include <fmt/core.h>
#include <vector>
struct Point {
int x, y;
};
template <typename O>
struct fmt::formatter<Point, O> : fmt::formatter<std::string_view, O> {
template <typename Ctx>
auto format(const Point& p, Ctx& ctx) const {
return fmt::format_to(ctx.out(), "(x:{}, y:{})", p.x, p.y);
}
};
int main() {
// Esempio base
fmt::print("Hello, {}! The answer is {}.\n", "world", 42);
// Formattazione con argomenti posizionali
fmt::print("I love {0} and {1}. {0} is great!\n", "pizza", "pasta");
// Formattazione di numeri con precisione
fmt::print("Value: {:.2f}\n", 3.14159);
// Formattazione di un vettore (richiede iterazione)
std::vector<int> numbers = {1, 2, 3, 4, 5};
fmt::print("Numbers: {}", fmt::join(numbers, ", "));
fmt::print("\n");
// Formattazione di un tipo personalizzato (Point)
Point p = {10, 20};
fmt::print("My point: {}\n", p);
// Scrittura su stringa (simile a stringstream)
std::string s = fmt::format("Formatted string: {}\n", "test");
fmt::print("{}", s);
return 0;
}
Compila ed esegui:
cmake -B build
cmake --build build
./build/my_app
L’output sarà:
Hello, world! The answer is 42.
I love pizza and pasta. pizza is great!
Value: 3.14
Numbers: 1, 2, 3, 4, 5
My point: (x:10, y:20)
Formatted string: test
Leggi anche: Zabbix 7 Installazione Ubuntu: Guida Completa e Configurazione (2026)
3. Funzionalità Avanzate e Best Practices
fmt offre molteplici funzionalità che vanno oltre la semplice formattazione di base. Ecco alcune che ho trovato particolarmente utili in ambienti di produzione:
- Formattazione su Buffer: Per scenari ad altissima performance,
fmt::format_toefmt::format_to_npermettono di scrivere direttamente su un buffer preallocato, evitando allocazioni dinamiche. - Logging:
fmtè una scelta eccellente per sistemi di logging. Puoi facilmente integrarefmt::printofmt::formatcon il tuo framework di logging esistente per output più veloci e sicuri. Leggi anche: Implementare un Sistema di Logging Efficace con rsyslog e ELK Stack - Localizzazione: Sebbene non sia una libreria di internazionalizzazione completa,
fmtsupporta la formattazione basata su locale per numeri e date, un aspetto cruciale in applicazioni globali. - Errori di Formattazione in Compilazione: Una delle caratteristiche più potenti è la capacità di
fmtdi rilevare molti errori di formattazione già in fase di compilazione, grazie all’uso di template e constexpr, riducendo il tempo di debug.
Un esempio di integrazione in un sistema di logging potrebbe essere:
#include <fmt/chrono.h>
#include <fmt/color.h>
#include <fmt/core.h>
#include <chrono>
void log_event(const std::string& level, const std::string& message) {
auto now = std::chrono::system_clock::now();
fmt::print(fmt::fg(fmt::color::gray), "[{:%Y-%m-%d %H:%M:%S}] ", now);
if (level == "ERROR") {
fmt::print(fmt::fg(fmt::color::red), "[{}] {}\n", level, message);
} else if (level == "WARNING") {
fmt::print(fmt::fg(fmt::color::yellow), "[{}] {}\n", level, message);
} else {
fmt::print(fmt::fg(fmt::color::green), "[{}] {}\n", level, message);
}
}
int main() {
log_event("INFO", "Application started.");
log_event("WARNING", "Disk space low: 15% remaining.");
log_event("ERROR", "Failed to connect to database.");
return 0;
}
Questo esempio mostra come fmt possa essere usato per creare output di log colorati e formattati con data/ora in modo efficiente. Leggi anche: Monitorare Server Linux Performance: 8 Strumenti a Confronto
Errori comuni e troubleshooting
fmt::formatvsfmt::print: Ricorda chefmt::formatrestituisce unastd::string, mentrefmt::printscrive direttamente sustdout. Scegli l’uno o l’altro in base a dove deve andare l’output. Usarefmt::formatper poi stampare concoutoprintfpuò annullare i benefici di performance difmt.- Mancanza di
find_package(fmt CONFIG REQUIRED)in CMake: Se ricevi errori di compilazione relativi afmto se il linker non trova i simboli, assicurati che il tuoCMakeLists.txtincluda correttamente la ricerca e il link alla libreriafmt. - Specificatori di formato errati: Sebbene
fmtsia type-safe, è comunque possibile commettere errori nella stringa di formato, specialmente con opzioni avanzate. Consulta sempre la documentazione ufficiale difmtlibper la sintassi corretta. Un errore comune è dimenticare di includerefmt/ostream.hse si vuole usarefmtcon tipi che hanno solooperator<<definito.
FAQ — Domande Frequenti
fmtlib è compatibile con i vecchi compilatori C++?
Sì, fmtlib supporta compilatori C++11 e successivi. La libreria è progettata per essere retrocompatibile, ma le funzionalità più recenti e le ottimizzazioni complete beneficiano di standard C++ più moderni (C++17, C++20).
Posso usare fmtlib per formattare output in file?
Assolutamente. fmt::print ha overload che accettano un FILE* come primo argomento, permettendoti di scrivere direttamente su file. Ad esempio, fmt::print(stderr, "Errore: {}\n", msg); scriverà su stderr.
Qual è la differenza principale tra fmtlib e la libreria di C++20?
fmtlib è la libreria standalone che ha ispirato e servito da base per la libreria standard di C++20. Molte delle funzionalità e della sintassi sono identiche. La principale differenza è che è parte dello standard e non richiede un'inclusione esterna, ma le versioni di fmtlib possono includere funzionalità più recenti o estensioni non ancora standardizzate.
fmtlib supporta la formattazione di date e orari?
Sì, fmt supporta la formattazione di date e orari attraverso l'header , che fornisce specificatori di formato simili a strftime ma con la sicurezza e la velocità di fmt.
Conclusioni con takeaway operativi
fmtlib/fmt rappresenta un salto di qualità nella gestione della formattazione del testo in C++. Abbandonare le vecchie abitudini di printf e iostream a favore di fmt non è solo una questione di modernità, ma un'esigenza pratica per chi sviluppa software C++ professionale. I benefici in termini di performance, sicurezza e leggibilità del codice sono tangibili e immediati. Adottare fmt significa prepararsi per il futuro dello standard C++ e migliorare la qualità del proprio codice oggi stesso. Se gestisci codebase C++ complesse, l'investimento di tempo per integrare fmt sarà ripagato rapidamente in meno bug e maggiore efficienza.
Fonti
Aggiornato: Settembre 2026