do_decimal_point 和 do_thousands_sep 不工作
do_decimal_point and do_thousands_sep Not Working
do_decimal_point
and do_thousands_sep
似乎完全被我的流忽略了。
我想要做的是在 get_money
. So I override moneypunct
中为我的 thousands_sep
使用一个句号,为我的 decimal_point
使用一个逗号,但它只是被忽略了:(
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
中放置一个断点时,它永远不会被击中。我不确定为什么不,但该信息似乎与问题相关。
这个解决方案实际上只是对 的解释。
moneypunct
实现删除了复制构造函数和赋值运算符。这为构建 punct_facet
:
留下了两个糟糕的选择
- 复制
punct_facet
中的所有moneypunct
成员,并在punct_facet
构造函数中调用所有moneypunct
虚函数来初始化它们。这有一个明显的缺点,即 punct_facet
对象比它应该的胖两倍,而且它的构造函数 运行 比绝对必要的要长。
- 使用指针和编译器特定的对象布局知识来实现从
moneypunct
到 punct_facet
的复制构造。这有一个明显的缺点,就是不能跨平台并且故意无视标准实现的设计。
对于这个答案,我选择了错误的选项 2,因为 moneypunct
的实现已经是特定于编译器的任何构造参数,除了:""
、"C"
或 "POSIX"
并且因为还有一个 open bug against the deleted moneypunct
copy constructor and assignment operator. (Incidentally if the moneypunct
construction argument is adjusted option 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
要使用默认构造函数,您需要在 main
顶部添加 cout.imdue(locale("en-US"));
并将 imdue
语句更改为:
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
中使用的参数之间的差异将再次导致您看到的意外行为。
do_decimal_point
and do_thousands_sep
似乎完全被我的流忽略了。
我想要做的是在 get_money
. So I override moneypunct
中为我的 thousands_sep
使用一个句号,为我的 decimal_point
使用一个逗号,但它只是被忽略了:(
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
中放置一个断点时,它永远不会被击中。我不确定为什么不,但该信息似乎与问题相关。
这个解决方案实际上只是对
moneypunct
实现删除了复制构造函数和赋值运算符。这为构建 punct_facet
:
- 复制
punct_facet
中的所有moneypunct
成员,并在punct_facet
构造函数中调用所有moneypunct
虚函数来初始化它们。这有一个明显的缺点,即punct_facet
对象比它应该的胖两倍,而且它的构造函数 运行 比绝对必要的要长。 - 使用指针和编译器特定的对象布局知识来实现从
moneypunct
到punct_facet
的复制构造。这有一个明显的缺点,就是不能跨平台并且故意无视标准实现的设计。
对于这个答案,我选择了错误的选项 2,因为 moneypunct
的实现已经是特定于编译器的任何构造参数,除了:""
、"C"
或 "POSIX"
并且因为还有一个 open bug against the deleted moneypunct
copy constructor and assignment operator. (Incidentally if the moneypunct
construction argument is adjusted option 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
要使用默认构造函数,您需要在 main
顶部添加 cout.imdue(locale("en-US"));
并将 imdue
语句更改为:
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
中使用的参数之间的差异将再次导致您看到的意外行为。