admin管理员组

文章数量:1336422

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?

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?

Share Improve this question asked Nov 20, 2024 at 5:05 康桓瑋康桓瑋 43.2k5 gold badges63 silver badges124 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

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|

godbolt

Unfortunately the C++ standard doesn't provide an equivalent to fmt::join but it is not difficult to implement one based on https://github/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.

本文标签: cWhat is the ideal way to customize the separators and brackets for formatting rangesStack Overflow