Strf allows you not only to add printable types, but also to override existing ones. The procedure is similar; the main difference is that instead of defining a PrintableDef type, you create a facet of the printable_overrider_c<…​> category, which is almost the same thing. So this document presumes you already know how to do add printables types. If you don’t, click here to get some explanation.

For example, one could define a facet to override the bool like this:

struct italian_bool_facet
{
    using category = strf::printable_overrider_c_of<bool>;

    template <typename CharT, typename Pre, typename FPack>
    constexpr static auto make_printer
        ( strf::tag<CharT>, Pre* pre, const FPack&, bool x ) noexcept
    {
        return strf::make_printer<CharT>
            ( pre
            , strf::pack()
            , strf::unsafe_transcode(x ? "vero" : "falso") );
    }

    template <typename CharT, typename Pre, typename FPack, typename…​ T>
    constexpr static auto make_printer
        ( strf::tag<CharT>
        , Pre* pre
        , const FPack& fp
        , strf::value_and_format<T...> x ) noexcept
    {
        return strf::make_printer<CharT>
            ( pre
            , fp
            , strf::unsafe_transcode(x.value() ? "vero" : "falso")
                .set_alignment_format(x.get_alignment_format()) );
    }
};

Everything in make_printer ( semantics, return type, arguments, etc ) is just like as in the PrintableDef requirements, except that here it is allowed to be non-static, though it must be then const ( so instead of hardcoded strings like "vero", and "falso" , we could use member variables, which would probably make more sense ).

Just as it is usual in PrintableDef classes, you can see that we have two make_printer fuctions. The second one handles bool values with formatting.

The format functions that are applicable to a printable type keep being the same when we override it. We can’t change them. Defining the format_specifiers type alias in the overrider facet has not effect.

Check in the documentation what are the format functions ( or the FormatSpecifiers ) applicable to the printable type you are overriding. If you take a look at the part the covers bool, you can see that we only need to handle alignment formatting. And that’s what we did in the implementation above.

Things are more lenient regarding facets: you can completely ignore the facet categories that influence the original printable type, as well as consider others or new ones. You can see that although bool type is influenced by lettercase facet, our override just ignores it.

Anyway, let’s see the result:

auto str = strf::to_string (italian_bool, true, '/', false);
assert(str == "vero/falso");

// and with formatting:
str = strf::to_string
    ( italian_bool
    , strf::center(true, 10, '.'), '/'
    , strf::center(false, 10, '.') );
assert(str == "...vero.../..falso...");

Some printable types are not overridable. A type X is only overridable if strf::printable_def_of<X>::is_overridable is std::true_type. An example of an non-overridable type is char. You can use strf::is_printable_and_overridable<X> to check at compile-time whether a type X is overridable.

You may be wondering why printable types are overriden this way, i.e. through facets. Couldn’t this library have adoped any of the usual customization point techniques available in C++? Well, the reason it is to avoid the situation where the overriding of a type could be activated by the mere inclusion of a header. After all, headers can be included unintentionally, and you don’t want to accidentaly change how a value is printed.