Integration of User-Defined Types

| Home | Libraries | People | FAQ | More

## 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 at al.

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

- for output Type needs to be Output Streamable;
- for input Type needs to be Input Streamable.

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 at 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);