【问题标题】:locale Facet Constructor Ignored语言环境方面构造函数被忽略
【发布时间】:2015-07-08 11:13:36
【问题描述】:

locale Facet constructor:

除了从参数 facet 安装的 Facet 类型的 facet(通常从参数的类型推断)之外,构造 other 的副本。如果 facet 为 NULL,则构造的语言环境是 other 的完整副本。以这种方式构建的语言环境没有名称。

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

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

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

我在任何编译器中都找不到针对此构造函数的任何错误。我认为我这样做是正确的。为什么我不能让locale 使用我的Facet 构造?

编辑:

the request of 0x499602D2 我添加了一个示例。有趣的是,Facet does 似乎被选中,但 notget_money 一起使用。我正在链接live example of this(它必须使用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&lt;char&gt; 不能被继承,因为它没有正确构造,除非它是由locale 在内部构造的。这至少在 Visual Studio 上是个问题,因为它通过grouping 确定是否使用thousands_sep。解决方法可能是完全重新实现moneypunct&lt;char&gt; 的功能。我现在正在修补它。同时我也在这里添加了一个错误:https://connect.microsoft.com/VisualStudio/feedback/details/1524749/inheriting-from-moneypunct-requires-use-of-unavailable-construction-information

【问题讨论】:

  • 能否请您提供一个 mcve?
  • @0x499602D2 我添加了一个示例,令我惊讶的是,它使这个问题无效......我需要对get_money 的工作原理进行更多研究。
  • 我得到了预期的输出here
  • @0x499602D2 令人着迷。然而,当我查看value 时只包含: 1. 所以即使 gcc 5.1.0 支持localeFacet 构造函数get_money 仍然不起作用。所以也许这应该写成针对 Visual Studio 2013 和 Clang 3.6.0 的错误。应该针对 gcc 5.1.0 编写一些其他错误。我想我应该继续这样做。

标签: c++ inheritance locale standards facets


【解决方案1】:

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

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

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

locale 的构造函数调用第二个moneypunct 构造函数。创建正确的_Locinfo 是问题的症结所在,因为该信息似乎是特定于实现的。 linked Visual Studio Bug 请求一种方法来构造函数moneypunct,而无需访问实现细节。所有 moneypunct 字段都必须代替此信息。

由于这个问题是关于扩展预期的工作moneypunct,最简单的方法是使用赋值运算符或复制构造函数。 坏消息:这两个都被删除了。所以punct_facet(const money_punct&amp;) 需要在内部编写以实现复制构造函数的行为。需要复制的值对应于所有需要覆盖的虚函数和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

这将导致punct_facet 看起来更像这样,因为 Visual Studio 将 v-table 指针作为对象布局中的第一项:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2020-03-29
    • 2019-10-25
    • 1970-01-01
    • 2011-05-27
    • 2020-11-07
    • 2014-12-26
    相关资源
    最近更新 更多