我的信息流似乎完全忽略了do_decimal_point
和do_thousands_sep
.
我想做的是在get_money
中使用一个句号作为我的Millennium_Sep和一个逗号作为我的小数点.因此,我重写了moneypunct
,但它只是被忽略了:(
struct punct_facet : public moneypunct<char> {
char_type do_decimal_point() const { return ','; }
char_type do_thousands_sep() const { return '.'; }
};
int main()
{
istringstream USCurrency("1,234.56 -1,234.56 1.234,56 -1.234,56");
USCurrency.imbue(locale(locale("en-US"), new punct_facet));
int index = 0;
long double value;
do{
value = 0.0;
USCurrency >> get_money(value, true);
cout << ++index << ": " << value << endl;
} while (value == 123456.0 || value == -123456.0);
return 0;
}
我希望这只会输出:
1: 123
但是我得到了:
1: 123456
2: -123456
3: 123
我究竟做错了什么?我正在使用Visual Studio 2013,以防从“ en-US”中显而易见.
编辑:
当我在do_decimal_point或do_thousands_sep中放置一个断点时,我发现它从未被击中.我不确定为什么不这样做,但是该信息似乎与问题有关.
解决方法:
该解决方案实际上只是对answer given here的解释.
货币构造函数删除了复制构造函数和赋值运算符.这给构造punct_facet留下了两个不好的选择:
>复制punct_facet中的所有moneypunct成员,并调用punct_facet构造函数中的所有moneypunct虚拟函数以对其进行初始化.这有一个明显的缺点,即punct_facet对象的胖度是其应有的两倍,并且其构造函数的运行时间超过了严格的要求.
>使用指针和特定于对象的编译器知识,以实现从moneypunct到punct_facet的复制构造.这具有明显的缺点,即不能跨平台,并且有意无视标准实现的设计.
对于这个答案,我选择了错误的选项2,因为moneypunct的实现已经是编译器所专有的,而不是“,”,“ C”或“ POSIX”以外的任何构造参数,并且因为针对已删除的moneypunct复制构造函数和赋值运算符. (顺便说一句,如果将moneypunct构造参数也调整为选项2 works in gcc 5.1.0,但在Clang 3.6.0中将不起作用.)希望Microsoft会尽快为该错误提供更多功能的解决方法,并且我们将不必使用任何错误的选项.
因此,如果punct_facet这样实现:
template <typename T>
class punct_facet : public T {
private:
void Init(const T* money){
const auto vTablePtrSize = sizeof(void*);
memcpy(reinterpret_cast<char*>(this) + vTablePtrSize, reinterpret_cast<const char*>(money) + vTablePtrSize, sizeof(T) - vTablePtrSize);
}
protected:
typename T::char_type do_decimal_point() const {
return typename T::char_type(',');
}
typename T::char_type do_thousands_sep() const {
return typename T::char_type('.');
}
public:
punct_facet(){
Init(&use_facet<T>(cout.getloc()));
}
punct_facet(const T* money){
Init(money);
}
};
您可以使用punct_facet构造函数之一进行构造,您将获得预期的输出:
123
要使用默认构造函数,您需要添加cout.imdue(locale(“ en-US”));在main的顶部,并将您的适当陈述更改为:
USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>()));
要使用自定义构造函数,您只需要将imdue语句更改为:
USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>(&use_facet<moneypunct<char, true>>(locale("en-US")))));
最好使用默认构造函数,因为模板类型和构造函数参数之间的差异可能会导致某些不良行为.
值得注意的一点是,您的USCurrency不使用国际货币格式,因此无需使用moneypunct< char,true> ;, moneypunct< char>.会很好.只需记住要在各处进行更改,因为punct_facet的模板参数与get_money中使用的参数之间的差异将再次导致您所看到的意外行为.