Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Integration of User-Defined Types

Probably the most obvious way to support a new type is to write a converter (potentially by inheriting from an existing converter) that understands the type and implements whatever transformation functionality is required. That said, conversions to certain types are very common (for example, string/text-related conversions) and, consequently, an ability to extend support of an existing converter onto a user-defined type might be the preferred option. The obvious example of such design might be the std::iostream library and its type-integration mechanism based on

std::istream& operator>>(std::istream&, Type&);       // For input
std::ostream& operator<<(std::ostream&, Type const&); // For output

Within the Boost.Convert framework the integration and support of user-defined types is every converter's private business. Every converter is free to implement its own (or re-use an existing) user-type-integration mechanism.

boost::cnv::stream et al.

Unsurprisingly, the converters based on the std::iostream library use the mechanism introduced and supported by that library. That is,

which in practical terms means that the type needs to have the following operators defined:

std::istream& operator>>(std::istream&, Type&);       // For input
std::ostream& operator<<(std::ostream&, Type const&); // For output

For example,

struct change
{
    enum value_type { no, up, dn };

    change(value_type v =no) : value_(v) {}
    bool operator==(change v) const { return value_ == v.value_; }
    value_type value() const { return value_; }

    private: value_type value_;
};

std::istream& operator>>(std::istream& stream, change& chg)
{
    std::string str; stream >> str;

    /**/ if (str == "up") chg = change::up;
    else if (str == "dn") chg = change::dn;
    else if (str == "no") chg = change::no;
    else stream.setstate(std::ios_base::failbit);

    return stream;
}

std::ostream& operator<<(std::ostream& stream, change const& chg)
{
    return stream << (chg == change::up ? "up" : chg == change::dn ? "dn" : "no");
}

That allows handling conversions of user-defined types with std::iostream-based converters:

boost::cnv::cstream      cnv1;
boost::cnv::lexical_cast cnv2;

change chg = change::up;
string  s1 = convert<string>(chg, cnv1, "bad");                // Input type (change) deduced
string  s2 = convert<string, change>(change::dn, cnv1, "bad"); // Input type (change) enforced

BOOST_TEST(convert<change>("up", cnv1, change::no) == change::up);
BOOST_TEST(convert<change>("up", cnv2, change::no) == change::up);
BOOST_TEST(s1 == "up");
BOOST_TEST(s2 == "dn");

boost::cnv::strtol et al.

Other converters (based on boost::cnv::cnvbase) implement support for user types similarly but without the std::iostream-related overhead (see Converters Compared). Namely, new types are supported by the converters after the following is defined:

void operator>>(TypeIn const&, boost::optional<TypeOut>&);

For example, the mentioned change class is deployed with boost::cnv::strol after the following change-to-string and string-to-change conversions are defined:

inline void operator>>(change chg, boost::optional<std::string>& str)
{
    str = chg == change::up ? "up" : chg == change::dn ? "dn" : "no";
}

inline void operator>>(std::string const& str, boost::optional<change>& chg)
{
    /**/ if (str == "up") chg = change::up;
    else if (str == "dn") chg = change::dn;
    else if (str == "no") chg = change::no;
}

which are not that dissimilar to (but considerably more efficient than) previously shown:

std::istream& operator>>(std::istream&, change&);
std::ostream& operator<<(std::ostream&, change const&);

That allows handling conversions of user-defined types with boost::cnv::strtol:

boost::cnv::strtol cnv;
change          up_chg = change::up;
change          dn_chg = change::dn;

BOOST_TEST(convert<std::string>(up_chg, cnv, "bad") == "up");
BOOST_TEST(convert<std::string>(dn_chg, cnv, "bad") == "dn");
BOOST_TEST(convert<std::string>(    12, cnv, "bad") == "12");

BOOST_TEST(convert<change>("up", cnv, change::no) == change::up);
BOOST_TEST(convert<change>("dn", cnv, change::no) == change::dn);
BOOST_TEST(convert<   int>("12", cnv, -1) == 12);


PrevUpHomeNext