PrevUpHomeNext

Converters

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,
              std::bind(assign<int>, std::placeholders::_2,
                  std::bind(boost::lexical_cast<int, string>, std::placeholders::_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] Note

Converters shall be independent from and must not rely on the Boost.Convert infrastructure.

Implicit TypeIn Promotions and Conversions

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>


PrevUpHomeNext