本文介绍了do_decimal_point和do_thousands_sep不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

do_decimal_point do_thousands_sep 似乎被我的信息流完全忽略了.

do_decimal_point and do_thousands_sep seem to be completely ignored by my stream.

我想做的是在 get_money .因此,我覆盖了 moneypunct ,但它只是被忽略了:(

What I want is to do is use a period for my thousands_sep and a comma for my decimal_point in get_money. So I override moneypunct but it is just ignored :(

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;
}

我希望这只会输出:

但是我得到了:

我做错了什么?我正在使用Visual Studio 2013,以防"en-US"出现这种情况.

What am I doing wrong? I'm using Visual Studio 2013, in case that may be obvious from the "en-US".

当我在do_decimal_pointdo_thousands_sep中放置一个断点时,我发现它从未被击中.我不确定为什么不这样做,但是这些信息似乎与问题有关.

I've discovered when I place a break-point in do_decimal_point or do_thousands_sep that it is never hit. I'm not sure why not, but that information seems to be relevant to the problem.

推荐答案

此解决方案实际上只是对此处给出的答案的解释.

This solution is really just an explanation of the answer given here.

moneypunct实现将复制构造函数和赋值运算符都删除.这给构造punct_facet留下了两个不好的选择:

Both the copy constructor and assignment opperator are deleted by the moneypunct implementation. Which leaves two bad options for constructing punct_facet:

  1. 复制punct_facet中的所有moneypunct成员,并在punct_facet构造函数中调用所有moneypunct虚函数以对其进行初始化.这样做有一个明显的缺点,就是punct_facet对象的肥胖是其应有的两倍,并且其构造函数的运行时间超过了严格的要求.
  2. 使用指针和特定于编译器的对象布局知识来实现​​从moneypunctpunct_facet的副本构造.这样做的明显缺点是无法跨平台,并且有意无视标准实现的设计.
  1. Duplicate all moneypunct members in punct_facet and call all moneypunct virtual functions in the punct_facet constructor to initialize them. This has the obvious drawback of a punct_facet object being twice as fat as it should be and it's constructor running longer than is strictly necessary.
  2. Use pointers and a compiler specific knowledge of object layout to effect a copy construction from a moneypunct to a punct_facet. This has the obvious drawback of not being cross-platform and intentionally disregarding the standard implementation's design.

对于这个答案,我选择了错误的选项2,因为moneypunct的实现已经是编译器特定于除"""C""POSIX"以外的任何构造参数的,并且因为存在打开错误针对已删除的moneypunct复制构造函数和赋值运算符. (顺便说一句,如果moneypunct构造参数已调整,选项2 在gcc 5.1.0中起作用,但在Clang 3.6.0中将不能.)希望Microsoft会尽快为该错误提供更多功能的解决方法,而我们也不必使用任何错误的选择.

For this answer I have elected bad option 2, because the implementation of moneypunct is already compiler specific for any construction argument other than: "", "C", or "POSIX" and because there is an 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 as well, but it will not work in Clang 3.6.0.) Hopefully Microsoft will provide a more functional workaround for that bug soon and we won't have to use either bad option.

因此,如果punct_facet是这样实现的:

So if punct_facet is implemented like this:

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构造函数进行构造,您将获得预期的输出:

You can construct with either of the punct_facet constructors and you will get your expected output:

要使用默认构造函数,您需要在main的顶部添加cout.imdue(locale("en-US"));并将imdue语句更改为:

To use the default constructor you'd need to add cout.imdue(locale("en-US")); at the top of main and change your imdue statement to:

USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>()));

要使用自定义构造函数,只需要将imdue语句更改为:

To use the custom constructor you'd only need to change your imdue statement to:

USCurrency.imbue(locale(locale("en-US"), new punct_facet<moneypunct<char, true>>(&use_facet<moneypunct<char, true>>(locale("en-US")))));

最好使用默认构造函数,因为模板类型与构造函数参数之间的差异可能会导致某些不良行为.

The default constructor is preferable as a discrepancy between your template type and your constructor argument could result in some bad behavior.

一个小注释,您的USCurrency没有使用国际货币格式,因此无需使用moneypunct<char, true>moneypunct<char>可以正常工作.只需记住要对其进行任何更改,因为punct_facet的模板参数与get_money中使用的参数之间的差异将再次导致您所看到的意外行为.

One minor note, your USCurrency is not using international currency format, so there's no need to use moneypunct<char, true>, moneypunct<char> will work just fine. Just remember to change it everywhere as a discrepancy between the template arguments to punct_facet and the arguments used in get_money will again result in the unexpected behavior you were seeing.

这篇关于do_decimal_point和do_thousands_sep不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 08:53