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_pointdo_thousands_sep 中放置一个断点时,它永远不会被击中。我不确定为什么不,但该信息似乎与问题相关。

这个解决方案实际上只是对 的解释。

moneypunct 实现删除了复制构造函数和赋值运算符。这为构建 punct_facet:

留下了两个糟糕的选择
  1. 复制punct_facet中的所有moneypunct成员,并在punct_facet构造函数中调用所有moneypunct虚函数来初始化它们。这有一个明显的缺点,即 punct_facet 对象比它应该的胖两倍,而且它的构造函数 运行 比绝对必要的要长。
  2. 使用指针和编译器特定的对象布局知识来实现​​从 moneypunctpunct_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 中使用的参数之间的差异将再次导致您看到的意外行为。