The C++ Standard Library provides the std::locale
class
( used to manage facet object ), as well as the std::numpunct
class
template. So, why did Strf define its own
facets design ( and its own strf::numpunct
) instead of just using
what is already well-know and available by the standard ?
To start with, std::locale
has the some disadvantages:
-
It forces the use dynamic memory allocation.
-
It requires RTTI and exceptions enabled
-
It’s not available in freestanding implementations.
These things may be irrelevant in many scenarios,
but they are problematic in others.
They were probably unavoidable back
in the time std::locale
was created,
but we can do better now with modern C++.
The design of strf::facets_pack
class template is similar
to as of std::tuple
, holding its elements by value,
in contrast to std::locale
were they
are managed through reference counting.
strf::get_facet
is as fast as a typical getter: it
just returns the reference of the requested object, or,
if it is not present, a default value,
while std::get_facet
probably needs
to perform some run-time processing.
There is no base class that facets in Strf need to derive from. They only need to satisfy the Facet type requirements, which is not really demanding. This provides a great flexibility on how a facet can be designed. It can be as simple as an enumeration or as sofisticated as the the charset facets, or the width calculation facets. But one thing all facet of this library have in common is that they all are small and fast to copy, and none of them cause dynamic memory allocation.
strf::numpunct
also has some advantages in relation to std::numpunct
:
-
The decimal point and the thousands separator are
char32_t
values. -
Punctuation can also be applied on integers printed in hexadecimal, octal or binary bases.
-
A single
strf::numpunct
object works for all character types. -
The grouping is defined in a simple integer, which is way more lightweight than using a
std::string
. -
Less boiler plate to manually define the punctuation: no need to create a new class that overrides member functions. You do it in a single expression:
auto punct = strf::numpunct<10> (3, 2, 1) .decimal_point(',') .thousands_separator('.');
( Be aware that strf::numpunct
does not affect bool
values,
contrary to std::numpunct
which
has the truename()
and falsename()
functions.
If you what to change how bool
values are printed,
see how to override printable types.
Furthermore, std::locale
and strf::facets_pack
have been created with
different goals in mind. std::locale
is about localization,
and it was designed to be used in std::iostream
.
Strf facets were created to make Strf highly customizable,
kind of a complement to format functions.
Dealing with numeric punctuation just happens to be one thing
they have in common.