locale构面方法忽略 [英] locale Facet Constructor Ignored

查看:199
本文介绍了locale构面方法忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

地区 Facet 构造函数


构造面的类型Facet(通常从参数类型中推导出),它是从参数facet安装的。如果facet为NULL,则构造的语言环境是其他语言的完整副本。以这种方式构造的语言环境没有名称。


我尝试使用 Facet 这里,但是当我把一个在 do_decimal_point do_thousands_sep 中的断点不会被调用:(



我可以看到 Facet 被传入,但它被传递到标准库实现文件,所以我不能看到是否有任何东西。 / p>

我在Visual Studio 2013,Clang 3.6.0和gcc 4.9.2上尝试过了。所有从未在 Facet 中使用其他语言环境的行为传递。



我在任何编译器中找不到任何对这个构造函数的错误。我想我正在这样做,为什么我不能得到 locale 使用我的 Facet



EDIT:

请求0x499602D2 < a>我添加了一个例子。有趣的是, 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(en-US),new Foo)

const moneypunct< char> * temp =& use_facet< std :: moneypunct< char>>(cout.getloc());

cout<< temp-> decimal_point()<< endl temp-> thousand_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;
}



此输出:



< blockquote>

命中Foo :: do_thousands_sepHit Foo :: do_decimal_point,


我希望它输出:


点击Foo :: do_thousands_sepHit Foo :: do_decimal_point,


Hit Foo :: do_thousands_sepHit Foo :: do_decimal_point


EDIT2: b
$ b

看起来 moneypunct< char> 不能继承,因为它没有被正确构造,除非它是内部构造由 locale 。至少在Visual Studio是一个问题,因为它决定是否使用 thousands_sep 分组。有关的工作可能是完全重新实现 moneypunct< char> 的功能。我现在正在修补。在此期间,我还在此添加了一个错误: https://connect.microsoft.com/VisualStudio/feedback/details/1524749/inheriting-from-moneypunct-requires-use-of-unavailable-construction-information <事实上, do_decimal_place do_thousands_place


解决方案

/ code> 尊重 get_money 。困难在于,正在继承的 moneypunct 是默认构造的,所以支持信息指向 get_money 调用 do_decimal_place do_thousands_place 未设置。



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


  1. code> moneypunct()

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

locale 的构造函数调用第二 moneypunct 构造函数。创建一个正确的 _Locinfo 是问题的症结所在,因为信息似乎是实现特定的。 链接的视觉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.frac_digits()),
m_pos_format(defaultFacet.pos_format()),
(默认Facet.pos_format())
m_negative_sign(defaultFacet.negative_sign b m_neg_format(defaultFacet.neg_format()){}
};



编辑



此解决方案是跨平台的,但也不能令人满意,因为必须添加到 punct_facet 中的所有成员已存在 c $ c> moneypunct 。我不知道这种肥胖的一个干净的解决方法。您可以在这里找到特定于编译器的hack: http://stackoverflow.com/a/31454039/2642059



这将导致一个 punct_facet 看起来更像这样的Visual Studio放置v表指针作为第一个项目在对象布局:

  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


The locale Facet constructor:

Constructs a copy of other except for the facet of type Facet (typically deduced from the type of the argument) which is installed from the argument facet. If facet is NULL, the constructed locale is a full copy of other. The locale constructed in this manner has no name.

I try to construct using my Facet here, but when I put a break-point in my do_decimal_point and do_thousands_sep they are never called :(

I can see the Facet being passed in, but it's passed into standard library implementation files so I can't see if anything is ever done with it.

I've tried this on Visual Studio 2013, Clang 3.6.0, and gcc 4.9.2. All of them behave as though I had never passed in a Facet just using the other locale's behavior.

I can't find any bugs against this constructor in any of the compilers. I think I'm doing this all the right way. Why can't I get locale to construct using my Facet?

EDIT:

At the request of 0x499602D2 I have added an example. It's interesting to note that the Facet does seem to be picked up but not used with get_money. I'm linking a live example of this (which necessarily useslocale("C") instead of 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;
}

This outputs:

Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.

I would expect it to output:

Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.
Hit Foo::do_thousands_sepHit Foo::do_decimal_point

EDIT2:

It appears that moneypunct<char> can't be inherited from as it doesn't get constructed properly, unless it is constructed internally by the locale. Which at least on Visual Studio is a problem because it determines whether to use thousands_sep by the grouping. The work around may be to completely reimplement moneypunct<char>'s functionality. I'm tinkering with that now. In the meantime I've also added a bug here: https://connect.microsoft.com/VisualStudio/feedback/details/1524749/inheriting-from-moneypunct-requires-use-of-unavailable-construction-information

解决方案

The fact is, do_decimal_place and do_thousands_place are respected by get_money. The difficulty is in the fact that the moneypunct that is being inherited from is being default constructed, so the supporting information to direct get_money to call do_decimal_place and do_thousands_place is not being set up.

Visual Studio's implementation of moneypunct provides two public constructors:

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

locale's constructor calls the 2nd moneypunct constructor. Creating a proper _Locinfo is the crux of the problem as that information seems to be implementation specific. The linked Visual Studio Bug requests a way to construct a functional moneypunct without access to implementation details. In lieu of this information all moneypunct fields must be cooked up.

Since this question is about extending an expected working moneypunct the easiest way to do that would be to use an assignment operator or copy constructor. Bad news: both of those are deleted. So punct_facet(const money_punct&) will need to be written internally implementing the behavior of a copy constructor. The values that need to be copied correspond to all the virtual functions that need to be overridden and by punct_facet. In the end your class will end up looking similar to this:

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()) {}
};

EDIT:

This solution is cross platform but it is also unsatisfactory, because all the members that had to be added to punct_facet already exist in moneypunct. I am not aware of a clean workaround for this fattening. A compiler specific hack is available here: http://stackoverflow.com/a/31454039/2642059

This would result in a punct_facet that looked more like this given that Visual Studio places the v-table pointer as the first item in the object layout:

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

Incidentally this implementation of punct_facet is not supported in Clang 3.6.0 but is supported in gcc 5.1.0: http://coliru.stacked-crooked.com/a/e4a1d88b560d6d1b

这篇关于locale构面方法忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆