语言环境构面构造函数被忽略
locale Facet Constructor Ignored
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.
我尝试使用我的 Facet
进行构造,但是当我在我的 do_decimal_point
和 do_thousands_sep
中放置一个断点时,它们永远不会被调用 :(
我可以看到 Facet
被传入,但它被传递到标准库实现文件中,所以我看不到是否对它做过任何事情。
我已经在 Visual Studio 2013、Clang 3.6.0 和 gcc 4.9.2 上试过了。 它们中的所有 的行为就好像我从未通过 Facet
只是使用另一个 locale
的行为。
我在任何编译器中都找不到针对此构造函数的任何错误。我认为我这样做是对的。为什么我不能让 locale
使用我的 Facet
进行构建?
编辑:
在 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(必须使用 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;
}
这输出:
Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.
我希望它输出:
Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.
Hit Foo::do_thousands_sepHit Foo::do_decimal_point
编辑2:
看来 moneypunct<char>
无法继承,因为它没有正确构造,除非它是由 locale
内部构造的。这至少在 Visual Studio 上是一个问题,因为它决定了是否由 grouping
使用 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
受到get_money
的尊重。困难在于被继承的 moneypunct
是默认构造的,所以指导 get_money
调用 do_decimal_place
和 do_thousands_place
的支持信息不是设置。
Visual Studio 对 moneypunct
的实现提供了两个 public 构造函数:
moneypunct()
moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)
locale
的构造函数调用第二个 moneypunct
构造函数。创建适当的 _Locinfo
是问题的关键,因为该信息似乎是特定于实现的。 linked Visual Studio Bug 请求一种构建功能性 moneypunct
的方法,而无需访问实现细节。代替此信息,所有 moneypunct
字段都必须经过处理。
因为这个问题是关于扩展预期的工作 moneypunct
最简单的方法是使用赋值运算符或复制构造函数。 坏消息:这两个都被删除了。所以 punct_facet(const money_punct&)
需要在内部编写来实现复制构造函数的行为。需要复制的值对应所有需要被覆盖的虚函数punct_facet
。最后,您的 class 看起来将类似于:
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:
如果 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);
}
};
顺便提一下,Clang 3.6.0 不支持 punct_facet
的实现,但 gcc 5.1.0 支持 :http://coliru.stacked-crooked.com/a/e4a1d88b560d6d1b
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.
我尝试使用我的 Facet
do_decimal_point
和 do_thousands_sep
中放置一个断点时,它们永远不会被调用 :(
我可以看到 Facet
被传入,但它被传递到标准库实现文件中,所以我看不到是否对它做过任何事情。
我已经在 Visual Studio 2013、Clang 3.6.0 和 gcc 4.9.2 上试过了。 它们中的所有 的行为就好像我从未通过 Facet
只是使用另一个 locale
的行为。
我在任何编译器中都找不到针对此构造函数的任何错误。我认为我这样做是对的。为什么我不能让 locale
使用我的 Facet
进行构建?
编辑:
在 Facet
does seem to be picked up but not used with get_money
. I'm linking a 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;
}
这输出:
Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.
我希望它输出:
Hit Foo::do_thousands_sepHit Foo::do_decimal_point,
.
Hit Foo::do_thousands_sepHit Foo::do_decimal_point
编辑2:
看来 moneypunct<char>
无法继承,因为它没有正确构造,除非它是由 locale
内部构造的。这至少在 Visual Studio 上是一个问题,因为它决定了是否由 grouping
使用 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
受到get_money
的尊重。困难在于被继承的 moneypunct
是默认构造的,所以指导 get_money
调用 do_decimal_place
和 do_thousands_place
的支持信息不是设置。
Visual Studio 对 moneypunct
的实现提供了两个 public 构造函数:
moneypunct()
moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)
locale
的构造函数调用第二个 moneypunct
构造函数。创建适当的 _Locinfo
是问题的关键,因为该信息似乎是特定于实现的。 linked Visual Studio Bug 请求一种构建功能性 moneypunct
的方法,而无需访问实现细节。代替此信息,所有 moneypunct
字段都必须经过处理。
因为这个问题是关于扩展预期的工作 moneypunct
最简单的方法是使用赋值运算符或复制构造函数。 坏消息:这两个都被删除了。所以 punct_facet(const money_punct&)
需要在内部编写来实现复制构造函数的行为。需要复制的值对应所有需要被覆盖的虚函数punct_facet
。最后,您的 class 看起来将类似于:
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:
如果 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);
}
};
顺便提一下,Clang 3.6.0 不支持 punct_facet
的实现,但 gcc 5.1.0 支持 :http://coliru.stacked-crooked.com/a/e4a1d88b560d6d1b