In C++23, we can use std::print
directly to print ranges thanks to P2286:
std::vector v = {10, 2, 42, 15};
std::println("{::02X}", v); /* 02X is the format spec for elements of range */
which gives:
[0A, 02, 2A, 0F]
However, if I want to customize the brackets and separator to "|"
and "-"
respectively:
|0A-02-2A-0F|
How should I do this? I know that std::range_formatter
provides two custom APIs, set_brackets()
and set_separator()
, so the intuitive way seems to specialize std::formatter
:
template<class T, class charT>
struct std::formatter<std::vector<T>, charT> : std::range_formatter<T, charT> {
constexpr formatter() {
this->set_brackets("|", "|");
this->set_separator("-");
}
};
which gives the expected results.
But I wonder if there is a best practice for this, such as customizing brackets and separators directly using specific formatting strings (which the standard currently doesn't seem to support).
What is the recommended way to do this in the current standard? Is there an issue with the resolution of the question?
The {fmt} library, std::format
and std::print
are based on, provides fmt::join
which allows you to do this. For example:
#include <vector>
#include <fmt/ranges.h>
int main() {
std::vector v = {10, 2, 42, 15};
fmt::println("|{:02X}|", fmt::join(v, "-"));
}
prints
|0A-02-2A-0F|
Unfortunately the C++ standard doesn't provide an equivalent to fmt::join
but it is not difficult to implement one based on https://github.com/fmtlib/fmt/blob/df249d8ad3a9375f54919bdfa10a33ae5cba99a2/include/fmt/ranges.h#L620-L669.
You shouldn't specialize formatter
for types you don't own such as std::vector<T>
because it would conflict with the standard ones.