![](/img/trans.png)
[英]How to format floating point numbers with decimal comma using the fmt library?
[英]FMT - How to parse fmt format string for floating point format arguments?
我想在 fmt 中使用自定義十進制數字類型。 十進制類型使用它自己的方法生成一個 output 字符串。 我無法理解如何解析超出單個字符的上下文字符串,以獲得數字精度等。然后我可以將其發送到字符串方法,以生成相關的 output,然后在返回結果時將其傳遞給字符串格式化程序. 自定義類型不包含原生浮動類型直接格式化。 轉換為本機類型也不起作用,因為小數可能具有比本機類型更大的指數或精度。
根據文檔,我不確定這是可能的。 或者我沒有朝着正確的方向前進。
提前感謝您的任何澄清!
template<>
struct std::formatter<Number> {
Format_Args fmt;
constexpr auto parse(std::format_parse_context& context) {
auto it = context.begin();
auto end = context.end();
if (it != end && (*it == 'f' || *it == 'e')) {
fmt.type = *it++;
}
return it;
}
template<typename Context>
constexpr auto format(const Number n, Context& context) {
return formatter<std::string>::format(n.to_string(fmt), context);
}
};
我查看了 API 文檔,沒有成功。 還查看了 fmt 標記的帖子,尋找答案。 這篇文章,接近我正在尋找的東西。 但沒有評論如何解析多個 arguments 或變量 arguments。
閱讀本教程后想通了。 雖然它沒有直接回答我的問題。 它確實讓我找到了一種方法來捕獲為上下文發送的所有文本格式。
然后我可以在格式化方法中根據需要解析它。 下面是一個簡單的例子,說明如何將解析后的文本捕獲到一個向量中,以便稍后進行處理。 在這里可以簡單地將它們輸出到 std:ostream output。
namespace std {
struct Color {
uint8_t r{ 0 };
uint8_t g{ 0 };
uint8_t b{ 0 };
};
template <>
struct std::formatter<Color> {
std::vector<char> context;
constexpr auto parse(std::format_parse_context& ctx) {
auto pos = ctx.begin();
while (pos != ctx.end() && *pos != '}') {
context.push_back(*pos);
++pos;
}
return pos; // This must be '}'.
}
auto format(const Color& col, std::format_context& ctx) {
bool hex = false;
for (auto c : context) {
std::cout << c;
if (c == '!') {
std::cout << "\n";
}
if (c == 'h' || c == 'H') {
hex = true;
}
}
std::cout << std::endl;
if (hex) {
uint32_t val = col.r << 16 | col.g << 8 | col.b;
return std::format_to(ctx.out(), "#{:x}", val);
}
return std::format_to(ctx.out(), "({}, {}, {})", col.r, col.g, col.b);
}
};
}
int main() {
Color a;
std::cout << std::format("{:Hello formatter!.50}", a) << std::endl;
std::cout << std::endl;
}
導致這個 output:
Hello formatter!
.50
#0
下面是更新的格式化程序,它編譯將解析后的 arguments 傳遞給我的 object class。請注意,所有解析都發生在編譯時。
namespace std {
template <>
struct std::formatter<Olly::MPA::Number> {
/*
In the base class is a format struct, to capture the relevant data.
It is defaulted to the argument values below.
struct Format_Args {
int base = 10;
char sign = '-';
char align = '<';
int width = -1;
int prec = -1;
char type = 'd';
char form = 'g';
char fill = '\0';
bool pref = false;
bool pad = false;
bool local = false;
};
*/
Olly::MPA::Number::Format_Args fmt;
constexpr auto parse(std::format_parse_context& ctx) {
bool prec_definition = false;
std::string arg_buffer;
auto pos = ctx.begin();
if (pos != ctx.end() && *pos != '}') {
char c = *pos;
if (c != '<' && c != '^' && c != '>') {
fmt.fill = c;
++pos;
}
if (fmt.fill == '\\' && c == '<' || c == '^' || c == '>') {
fmt.fill = c;
++pos;
}
}
while (pos != ctx.end() && *pos != '}') {
char c = *pos;
switch (c) {
case '<':
case '^':
case '>':
fmt.align = c;
break;
case '+':
case '-':
case ' ':
fmt.sign = c;
break;
case '#':
fmt.pref = true;
break;
case '0':
fmt.pad = true;
break;
case '.':
prec_definition = true;
fmt.width = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
arg_buffer = "";
break;
case 'L':
fmt.local = true;
break;
case 'b':
case 'B':
case 'd':
case 'D':
case 'o':
case 'O':
case 'x':
case 'X':
fmt.type = c;
break;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
fmt.type = c;
break;
default:
arg_buffer += c;
}
++pos;
}
if (prec_definition) {
fmt.prec = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
}
else {
fmt.width = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
}
return pos;
}
auto format(const Olly::MPA::Number& a, std::format_context& ctx) {
return std::format_to(ctx.out(), "{}", a.to_string(fmt));
}
};
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.