locale构面方法忽略 [英] locale Facet Constructor Ignored
问题描述
构造面的类型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>我添加了一个例子。有趣的是, 命中Foo :: do_thousands_sepHit Foo :: do_decimal_point, 我希望它输出: 点击Foo :: do_thousands_sepHit Foo :: do_decimal_point, EDIT2: b 看起来
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>
。
。
Hit Foo :: do_thousands_sepHit Foo :: do_decimal_point
$ 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
实现提供了两个公共构造函数:
- code> moneypunct()
-
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/e4a1d88b560d6d1bConstructs 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 mydo_decimal_point
anddo_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 otherlocale
'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 myFacet
?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 withget_money
. I'm linking a live example of this (which necessarily useslocale("C")
instead oflocale("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_pointEDIT2:
It appears that
moneypunct<char>
can't be inherited from as it doesn't get constructed properly, unless it is constructed internally by thelocale
. Which at least on Visual Studio is a problem because it determines whether to usethousands_sep
by thegrouping
. The work around may be to completely reimplementmoneypunct<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
anddo_thousands_place
are respected byget_money
. The difficulty is in the fact that themoneypunct
that is being inherited from is being default constructed, so the supporting information to directget_money
to calldo_decimal_place
anddo_thousands_place
is not being set up.Visual Studio's implementation of
moneypunct
provides two public constructors:
moneypunct()
moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)
locale
's constructor calls the 2ndmoneypunct
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 functionalmoneypunct
without access to implementation details. In lieu of this information allmoneypunct
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. Sopunct_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 bypunct_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 inmoneypunct
. I am not aware of a clean workaround for this fattening. A compiler specific hack is available here: http://stackoverflow.com/a/31454039/2642059This 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屋!