What Is dynamic_format_specs in fmtlib and How Does It Work
dynamic_format_specs is a template struct in include/fmt/core.h that extends the standard format_specs class with two arg_ref members—width_ref and precision_ref—enabling deferred resolution of width and precision values from runtime arguments.
The {fmt} library (also known as fmtlib/fmt) supports dynamic format specifications where field width and precision are determined at runtime rather than compile time. This capability is implemented through the dynamic_format_specs structure, which decouples format string parsing from value resolution to enable format string reuse and pre-compilation.
Defining dynamic_format_specs in core.h
The dynamic_format_specs template is defined at lines 1286-1290 in include/fmt/core.h. It inherits from format_specs and adds two additional members that store references to arguments rather than concrete integer values.
template <typename Char = char>
struct dynamic_format_specs : format_specs {
arg_ref<Char> width_ref;
arg_ref<Char> precision_ref;
};
This design allows the format parser to record where to find the width and precision values (either by index or name) without actually fetching the values during the initial parse phase.
The arg_ref Mechanism
The width_ref and precision_ref members are instances of arg_ref<Char>, a variant-like template class that can hold either:
- An integer index referring to a positional argument
- A string identifier referring to a named argument
When the parser encounters dynamic syntax like "{:{}}" or "{:{precision}}", it populates these arg_ref objects with the appropriate reference instead of storing the immediate numeric value in the base format_specs structure.
How Dynamic Format Specifications Work
Parsing Dynamic Width and Precision
When parsing a format string containing runtime-dependent width or precision, the library creates a dynamic_format_specs<> instance rather than a plain format_specs. According to the unit tests in test/core-test.cc (lines 506-508), the parser identifies dynamic fields by detecting empty braces {} or named references within the format specification portion of the format string.
For example, in the format string "{:*>{}}":
- The
*character specifies a fill character - The
>specifies right alignment - The second
{}indicates that the width should be taken from the next argument
The parser stores this reference in specs.width_ref without evaluating the actual integer value.
Runtime Resolution with resolve_dynamic_spec
During the formatting phase, the library resolves these dynamic references through internal helpers such as detail::resolve_dynamic_spec (implemented in include/fmt/format.h). This function:
- Examines
specs.width_reforspecs.precision_ref - Retrieves the actual integer value from the argument store using the stored index or name
- Assigns the resolved value to the base class members
specs.widthorspecs.precision - Proceeds with standard formatting using the now-concrete values
This deferred resolution architecture is critical for dynamic_format_arg_store (defined in include/fmt/args.h), which allows building argument lists programmatically while reusing pre-parsed format specifications.
Practical Implementation Example
The following example demonstrates manual construction and usage of dynamic_format_specs to format a string with runtime-determined width and precision:
#include <fmt/core.h>
#include <fmt/format.h>
#include <string>
int main() {
// Create dynamic format specifications
fmt::detail::dynamic_format_specs<char> specs;
// Configure dynamic references: width from argument 1, precision from argument 2
specs.width_ref = fmt::detail::arg_ref<char>(1);
specs.precision_ref = fmt::detail::arg_ref<char>(2);
specs.align() = fmt::align::right;
// Prepare arguments: value, width, precision
auto args = fmt::make_format_args(3.14159, 10, 2);
// Format with dynamic specifications
std::string result = fmt::detail::vformat("{:{}}", args, specs);
// Result: " 3.14" (width 10, precision 2, right-aligned)
return 0;
}
In this example, the same specs object can be reused with different argument sets, demonstrating the efficiency gains of separating parsing from value resolution.
Benefits of Using dynamic_format_specs
Performance Through Pre-compilation: Because dynamic_format_specs stores references rather than values, parsed format strings can be cached and reused with different argument sets without re-parsing the format string syntax.
Support for FMT_COMPILE: Dynamic specifications work with compile-time format strings (FMT_COMPILE), allowing the library to validate format syntax at compile time while still permitting runtime-determined field widths and precisions.
Flexibility with Named Arguments: The arg_ref mechanism supports both positional indices and named references, enabling expressive APIs where users specify precision via names like "{value:{precision}}" rather than numeric indices.
Summary
dynamic_format_specsextendsformat_specsininclude/fmt/core.h(lines 1286-1290) withwidth_refandprecision_refmembers.- The struct uses
arg_ref<Char>to store references to arguments supplying dynamic width and precision values. - Resolution occurs at formatting time via
detail::resolve_dynamic_specininclude/fmt/format.h, fetching actual values from the argument store. - This architecture enables format string pre-compilation and reuse with
dynamic_format_arg_storefrominclude/fmt/args.h. - Implementation supports both positional (
{}) and named ({name}) dynamic references while maintaining compatibility with compile-time format string validation.
Frequently Asked Questions
What is the difference between format_specs and dynamic_format_specs?
format_specs stores concrete formatting parameters such as fill character, alignment, and static width/precision as immediate values. dynamic_format_specs inherits from format_specs but replaces static width and precision with arg_ref objects that store references to runtime arguments, allowing the same parsed specification to be used with different numeric values across multiple formatting operations.
How does fmtlib resolve dynamic width at runtime?
The library invokes internal helpers like detail::resolve_dynamic_spec during the formatting phase. This function inspects the width_ref member of the dynamic_format_specs object, retrieves the corresponding integer value from the argument list (whether stored by index or name), and assigns that value to the base class width member before the actual formatting output is generated.
Can dynamic_format_specs be used with compile-time format strings?
Yes. The separation of parsing and resolution allows dynamic_format_specs to work with FMT_COMPILE and other compile-time format string features. The format string syntax is validated at compile time, while the actual width and precision values are fetched from arguments at runtime, providing both safety and flexibility.
Where is dynamic_format_specs defined in the source code?
The template struct is defined at lines 1286-1290 in include/fmt/core.h. Related parsing logic appears in include/fmt/format.h, while usage examples and unit tests are located in test/core-test.cc (specifically around lines 506-508). The complementary dynamic_format_arg_store class is defined in include/fmt/args.h.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →