locale Facet Constructor Ignored

前端 未结 1 514
天涯浪人
天涯浪人 2021-01-16 13:42

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

相关标签:
1条回答
  • 2021-01-16 13:59

    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: https://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

    0 讨论(0)
提交回复
热议问题