![]() |
Home | Libraries | People | FAQ | More |
The boost::convert()
API plays its role by providing a uniform interface and
ensuring consistent behavior. However, it is the respective
converter which does the hard work of actual type conversion/transformation.
Boost.Convert design reflects the fact that no one converter is to satisfy all imaginable conversion/transformation-related user requirements. Consequently, extendibility and converter pluggability are important properties of Boost.Convert. The library provides several converters for common type conversions with varying degrees of formatting support and performance. However, it is an expectation that more generic-purpose and custom-specific converters are to be written and deployed with Boost.Convert.
For a converter to be plugged in to the Boost.Convert framework it needs to be a callable with one of the signatures:
template<typename TypeOut, typename TypeIn> void operator()(TypeIn const& value_in, boost::optional<TypeOut>& result_out) const; template<typename TypeOut, typename TypeIn> void operator()(TypeIn value_in, boost::optional<TypeOut>& result_out) const;
if that is a general-purpose converter capable of handling many types (like string-to-type and type-to-string conversions). Alternatively, a purpose-built custom converter might only care to provide
void operator()(TypeIn const&, boost::optional<TypeOut>&) const;
if its sole purpose is to handle one specific conversion/transformation of
TypeIn to TypeOut. For example, a
converter from the operating-system-specific MBCS string format to the UCS-2
or UCS-4 (depending on wchar_t
size) might be one such example:
void operator()(std::string const&, boost::optional<std::wstring>&) const;
Alternatively again, an ad-hoc in-place callable might be provided as a converter. For example,
using std::string; using boost::lexical_cast; using boost::convert;
int v03 = convert<int>(str, boost::bind(assign<int>, _2, boost::bind(lexical_cast<int, string>, _1))).value_or(-1);
or an old-fashioned function:
void plain_old_func(string const& value_in, boost::optional<int>& value_out)
int v01 = convert<int>(str, plain_old_func).value_or(-1);
With regard to converters the Boost.Convert framework has been designed with the following requirement in mind:
![]() |
Note |
---|---|
Converters shall be independent from and must not rely on the Boost.Convert infrastructure. |
It is worth remembering that TypeIn in the signature should
be interpreted in the context of the potential implicit type promotions and
conversions allowed by the language. For example, depending
on the context the take_double
and take_int
converters below
might not do what is expected of them due to implicit int-to-double
promotion and value-destroying double-to-int conversion
applied by the compiler:
struct take_double { void operator()(double, boost::optional<string>&) const {}}; struct take_int { void operator()(int, boost::optional<string>&) const {}};
convert<string>(11, take_double()); // Compiler applies int-to-double promotion to call the converter. convert<string>(11.23, take_int()); // Compiler applies double-to-int implicit truncation.
boost::convert()
API does not modify TypeIn or interpret it in any way.
The passed-in value and its type are delivered to the underlying converter
as-is. Consequently, if potential implicit type promotions and conversions
are not desirable, then it is the converter's responsibility to address that
issue. For example, one way to disable implicit conversions might be:
struct double_only { // Declared for all types. template<typename TypeIn> void operator()(TypeIn, boost::optional<string>&) const; }; // Defined only for certain types. template<> void double_only::operator()<double>(double, boost::optional<string>&) const {}
convert<string>(11.23, double_only()); // Fine. // convert<string>(11, double_only()); // Fails: undefined reference to double_only::operator()<int>