BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslfmt_formattable

Provide a concept to check for the presence of a bsl::formatter.

Outline

Purpose

Provide a concept to check for the presence of a bsl::formatter.

Classes

Macros

Description

This component conditionally provides bsl::formattable, a concept that determines if a type has a formatter enabled for a given character type (i.e. char or wchar_t). The concept is defined only if concepts are available on the current platform. The macro BSL_FORMATTABLE_DEFINED may be used to determine if the concept is present or not.

Because this component requires concepts support it is not available portably on all platforms, therefore any portable use of this concept should make use of the appropriate preprocessor guards.

When is a Type Formattable?

A type is formattable if it can be used as a formatted argument of the bsl::format family of functions:

bsl::string fmtd = bsl::format("{}", MyType(42));
Definition bslstl_string.h:1252

That in turn works if there is a matching bsl::formatter specialization for that type, such as:

namespace bsl {
template <class t_CHAR>
class formatter<MyType, t_CHAR> ...
}
Definition bdlat_valuetypefunctions.h:939

Usage

In this section we show the intended use of this component.

Example: Verify the Presence of a bsl::formatter

Suppose we want to write different code depending on if a type has a formatter enabled, and fall back to using standard streaming if it does not.

First we create a type that supports streaming but not formatting with bsl::format:

struct Streamable {};
std::ostream& operator<<(std::ostream& os, const Streamable&) {
return os << "Streamable";
}
bsl::ostream & operator<<(bsl::ostream &stream, const bdlat_AttributeInfo &attributeInfo)

Then we demonstrate that this type is not formattable, but an int is. Since the concept may not exists (older compilers/standards) we need to protect the code with the preprocessor:

#ifdef BSL_FORMATTABLE_DEFINED
assert(false == (bsl::formattable<Streamable, char>));
assert(true == (bsl::formattable<int, char>));
#endif

Next we create a generic function to convert a value to string, center-aligned, and we provide two implementations, the first one for types that are formattable in case the concept exists, and just the stream-based variation if it does not.

template <class t_TYPE>
centeredIn(const t_TYPE& obj, size_t width)
#ifdef BSL_FORMATTABLE_DEFINED
requires (!bsl::formattable<t_TYPE, char>)
#endif
{
os << obj;
bsl::string s = os.str();
width = bsl::max(width, s.length());
const size_t allPadding = width - s.length();
s.insert(s.begin(), allPadding / 2, ' ');
s.append(allPadding - allPadding / 2, ' ');
return s;
}
size_type length() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7301
void swap(basic_string &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits const_iterator begin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:2792
basic_string & append(const basic_string &suffix)
Definition bslstl_string.h:6188
basic_ostringstream< char, char_traits< char >, allocator< char > > ostringstream
Definition bslstl_iosfwd.h:97

Then, if the concept is present, we define the format-based overload:

#ifdef BSL_FORMATTABLE_DEFINED
template <class t_TYPE>
centeredIn(const t_TYPE& obj, size_t width)
requires (bsl::formattable<t_TYPE, char>)
{
return bsl::format("{:^{}}", obj, width);
}
#endif

Finally, we can call the centeredIn function and let concepts select the right variation (if concepts are available):

bsl::string s = centeredIn(Streamable(), 14);
assert(s == " Streamable ");
s = centeredIn(42, 8);
assert(s == " 42 ");