std::moneypunct facet负数货币输出格式与pattern定义不一致的原因咨询
我最近在调试std::moneypunct facet的负数货币输出格式时遇到了一个困惑:明明从facet获取到的负数格式pattern顺序是symbol→sign→none→value,但实际输出的负数货币却是sign在前、symbol在后,想请教下这是为什么?
我的测试代码如下:
#include <locale> #include <fstream> #include <iomanip> #include <iostream> int main() { std::locale loc{ "en_US.utf8" }; std::cout << "Locale name: " << loc.name() << std::endl; std::cout << "Part field none: " << static_cast<uint32_t>(std::money_base::none) << std::endl; std::cout << "Part field space: " << static_cast<uint32_t>(std::money_base::space) << std::endl; std::cout << "Part field symbol: " << static_cast<uint32_t>(std::money_base::symbol) << std::endl; std::cout << "Part field sign: " << static_cast<uint32_t>(std::money_base::sign) << std::endl; std::cout << "Part field value: " << static_cast<uint32_t>(std::money_base::value) << std::endl; const auto& fct = std::use_facet<std::moneypunct<char, true>>(loc); if (!std::has_facet<std::moneypunct<char, true>>(loc)) { std::cout << "There is no facet!" << std::endl; return 1; } std::money_base::pattern neg_ptrn = fct.neg_format(); std::cout << "Pattern negative format field 0: " << static_cast<uint32_t>(neg_ptrn.field[0]) << std::endl; std::cout << "Pattern negative format field 1: " << static_cast<uint32_t>(neg_ptrn.field[1]) << std::endl; std::cout << "Pattern negative format field 2: " << static_cast<uint32_t>(neg_ptrn.field[2]) << std::endl; std::cout << "Pattern negative format field 3: " << static_cast<uint32_t>(neg_ptrn.field[3]) << std::endl; std::cout.imbue(loc); std::cout << "Money value: " << std::showbase << std::put_money(-12345678.0) << std::endl; return 0; }
运行后得到的输出:
Locale name: en_US.utf8 Part field none: 120 Part field space: 32 Part field symbol: 36 Part field sign: 43 Part field value: 118 Pattern negative format field 0: 36 Pattern negative format field 1: 43 Pattern negative format field 2: 120 Pattern negative format field 3: 118 Money value: -$123,456.78
从输出能看到,neg_format()返回的pattern顺序是symbol(36)→sign(43)→none(120)→value(118),但实际输出的负数货币却是-$123,456.78,也就是负号(sign)在美元符号(symbol)前面,这和pattern定义的顺序完全相反,这是怎么回事呢?
其实这个现象是因为C++标准允许std::moneypunct的实现根据目标locale的实际惯例,对pattern的输出顺序做微调,尤其是符号的位置。
对于en_US这个locale来说,当地的习惯就是把负号放在货币符号的前面来表示负数金额,所以即使neg_format()返回的pattern看起来是symbol在前、sign在后,常用的libstdc++实现会根据locale的惯例调整符号的位置,最终输出符合当地习惯的格式。
另外还要注意,std::money_base::pattern中的sign元素更多是用来指定符号与哪个组件关联,而不是严格的输出顺序。比如在这个例子里,pattern中的sign紧跟在symbol之后,其实是表示符号应该和货币符号放在同一组,而实现会根据locale的习惯决定符号是放在货币符号的前面还是后面——对于en_US来说,就是放在前面。
还有一点,pattern中的none元素表示可选的分隔空格,而en_US的负数货币格式不需要这个空格,所以这个元素被忽略了,最终输出里没有多余的空格。
总结一下:neg_format()返回的pattern是一个逻辑上的组件分组定义,而不是绝对的输出顺序,实现会结合locale的实际使用习惯来调整最终的输出格式,确保符合当地的货币表示规范。
备注:内容来源于stack exchange,提问作者Yury

