覆盖 std::locale 上的多个分面

Override more than one facet on std::locale

本文关键字:std locale 覆盖      更新时间:2023-10-16

是否可以覆盖std::local上的多个方面?

例如,举一个相当做作的例子:

#include <locale>
class NumberFacet : public std::numpunct<char>
{
protected:
    char do_decimal_point() const override
    {
        return '.';
    }
    char do_thousands_sep() const override
    {
        return ',';
    }
};
class MoneyFacet : public std::moneypunct<char>
{
protected:
    char do_decimal_point() const override
    {
        return '.';
    }
    char do_thousands_sep() const override
    {
        return ',';
    }
};

我知道我可以像这样覆盖std::locale的一个方面来创建一个新的locale变量。

std::locale locale(std::locale(), new NumberFacet());

我怎么也通过MoneyFacet

我不得不这样做似乎不令人满意:

std::locale locale(std::locale(std::locale(), new NumberFacet()), new MoneyFacet());

有没有更好的方法?

operator<<()符合

这种情况:

#include <locale>
template <typename T,                                                                                                                                                                                                                                                         
    typename = std::enable_if_t<                                                                                                                                                                                                                                              
        std::is_constructible<std::locale, std::locale, T*>::value                                                                                                                                                                                                            
    >                                                                                                                                                                                                                                                                         
>                                                                                                                                                                                                                                                                             
std::locale operator<<(const std::locale& locale, T* facet)                                                                                                                                                                                                                   
{                                                                                                                                                                                                                                                                             
    return {locale, facet};                                                                                                                                                                                                                                                   
}
int main()
{
    auto locale = std::locale{} << new MoneyFacet{} << new NumberFacet{};
    std::cout.imbue(locale);
    std::cout << 12345.67f << 'n';
    std::cout << 123456789u << 'n';
}

演示。

IOStreams 库没有为您提供更好的编写方式,但您可以利用递归来完成工作。由于注入新区域设置始终涉及从旧区域设置进行复制,因此您可以不断递归以使用提供的方面构建新的区域设置。

template<class...>struct types{constexpr types(){}};
template<class...Ts>constexpr types<Ts...> types_t{};
template<class L, class F>
L makeloc(L loc, types<F>, int) {
    return std::locale(loc, new F{});
}
template<class L, class F, class... Fs>
L makeloc(L loc, types<F, Fs...>, long) {
    return makeloc(std::locale(loc, new F{}), types_t<Fs...>, 0);
}
template<class S, class L, class... Fs>
void imbue(S& s, L loc, types<Fs...> facets) {
    s.imbue(makeloc(loc, facets, 0));
}
int main() {
    imbue(std::cout, std::locale(), types_t<MoneyFacet, NumberFacet /*, ... */>);
}