locale Facet构造函数被忽略

locale Facet Constructor Ignored

本文关键字:构造函数 Facet locale      更新时间:2023-10-16

locale Facet构造函数:

构造一个other的副本,除了从参数facet安装的facet类型(通常从参数类型推断)的facet。如果facet为NULL,则构造的区域设置是other的完整副本。以这种方式构造的区域设置没有名称。

我尝试在这里使用我的Facet来构建,但是当我在do_decimal_pointdo_thousands_sep中放置断点时,它们永远不会被调用:(

我可以看到Facet被传递进来,但它被传递到标准库实现文件中,所以我无法看到是否有任何事情被做过。

我已经在Visual Studio 2013, Clang 3.6.0和gcc 4.9.2上尝试过了。所有的行为就好像我从来没有传入一个Facet,只是使用了另一个locale的行为。

我在任何编译器中都找不到这个构造函数的任何错误。我觉得我这样做是对的。为什么我不能让locale构建使用我的Facet ?

编辑:

在0x499602D2的请求下,我添加了一个示例。有趣的是,Facet 确实似乎被拾取了,但不是与get_money一起使用的。我链接了一个活生生的例子(它必须使用locale("C")而不是locale("en-US")):

class Foo : public std::moneypunct<char> {
protected:
    char_type do_decimal_point() const {
        cout << "Hit Foo::do_decimal_point";
        return ',';
    }
    char_type do_thousands_sep() const {
        cout << "Hit Foo::do_thousands_sep";
        return '.';
    }
};
int main()
{
    cout.imbue(locale(locale("en-US"), new Foo));
    const moneypunct<char>* temp = &use_facet<std::moneypunct<char>>(cout.getloc());
    cout << temp->decimal_point() << endl << temp->thousands_sep() << endl;
    istringstream USCurrency("1,234.56 -1,234.56 1.234,56 -1.234,56");
    USCurrency.imbue(cout.getloc());
    long double value;
    USCurrency >> get_money(value, true);
    return 0;
}
这个输出:

点击Foo::do_thousands_sepHit Foo::do_decimal_point,
.

我希望它输出:

点击Foo::do_thousands_sepHit Foo::do_decimal_point,

。点击Foo::do_thousands_sepHit Foo::do_decimal_point

EDIT2:

看来moneypunct<char>不能继承,因为它没有得到正确的构造,除非它是由locale内部构造。这至少在Visual Studio上是一个问题,因为它决定了是否使用groupingthousands_sep。解决方法可能是完全重新实现moneypunct<char>的功能。我现在正在修补它。同时,我还在这里添加了一个bug: https://connect.microsoft.com/VisualStudio/feedback/details/1524749/inheriting-from-moneypunct-requires-use-of-unavailable-construction-information

事实是get_money尊重do_decimal_placedo_thousands_place 。困难在于继承的moneypunct是默认构造的,因此没有设置指导get_money调用do_decimal_placedo_thousands_place的支持信息。

Visual Studio的moneypunct实现提供了两个公共构造函数:

  1. moneypunct()
  2. moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)

locale的构造函数调用第二个moneypunct构造函数。创建适当的_Locinfo是问题的关键,因为该信息似乎是特定于实现的。链接的Visual Studio Bug要求在不访问实现细节的情况下构造功能性moneypunct。为了代替这些信息,所有moneypunct字段都必须编造出来。

既然这个问题是关于扩展预期的工作moneypunct,那么最简单的方法就是使用赋值操作符或复制构造函数。坏消息:这两个都被删除了。因此需要在内部编写punct_facet(const money_punct&)来实现复制构造函数的行为。需要复制的值对应于需要覆盖的所有虚函数和punct_facet。最后,您的类最终看起来像这样:

template <typename T>
class punct_facet : public T {
protected:
    typename T::string_type m_grouping;
    typename T::string_type m_curr_symbol;
    typename T::string_type m_positive_sign;
    typename T::string_type m_negative_sign;
    int m_frac_digits;
    typename T::pattern m_pos_format;
    typename T::pattern m_neg_format;
    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('.');
    }
    typename T::string_type do_grouping() const {
        return m_grouping;
    }
    typename T::string_type do_curr_symbol() const {
        return m_curr_symbol;
    }
    typename T::string_type do_positive_sign() const {
        return m_positive_sign;
    }
    typename T::string_type do_negative_sign() const {
        return m_negative_sign;
    }
    int do_frac_digits() const {
        return m_frac_digits;
    }
    typename T::pattern do_pos_format() const {
        return m_pos_format;
    }
    typename T::pattern do_neg_format() const {
        return m_neg_format;
    }
public:
    punct_facet(const T& defaultFacet) : m_grouping(defaultFacet.grouping()),
                                         m_curr_symbol(defaultFacet.curr_symbol()),
                                         m_positive_sign(defaultFacet.positive_sign()),
                                         m_negative_sign(defaultFacet.negative_sign()),
                                         m_frac_digits(defaultFacet.frac_digits()),
                                         m_pos_format(defaultFacet.pos_format()),
                                         m_neg_format(defaultFacet.neg_format()) {}
};
编辑:

这个解决方案是跨平台的,但它也不令人满意,因为所有必须添加到punct_facet 的成员已经存在于moneypunct 中。我不知道有什么干净的方法可以解决这个问题。这里有一个编译器特定的hack: https://stackoverflow.com/a/31454039/2642059

如果Visual Studio将v-table指针作为对象布局的第一项,那么这会导致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的实现在Clang 3.6.0中不支持,但在gcc 5.1.0中支持: http://coliru.stacked-crooked.com/a/e4a1d88b560d6d1b