Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

boost::cnv::stream Converter

Formatting Support
Numeric Base
Field Width, Fill Character and Adjustment
Leading Whitespace Characters
Format of Boolean Values
Locale Support
Supported String Types
Wide String
Custom String Types
The Default Constructible Type Requirement

The purpose of the converter is to provide conversion-related formatting and locale support not available with boost::lexical_cast. Advantages of deploying a std::stream-based conversion engine are:

The converter might be deployed as follows:

#include <boost/convert.hpp>
#include <boost/convert/stream.hpp>
#include <boost/detail/lightweight_test.hpp>

using std::string;
using boost::convert;

struct boost::cnv::by_default : boost::cnv::cstream {};

int    i2 = convert<int>("123").value();      // Throws when fails.
int    i3 = convert<int>("uhm").value_or(-1); // Returns -1 when fails.
string s2 = convert<string>(123).value();

BOOST_TEST(i2 == 123);
BOOST_TEST(i3 == -1);
BOOST_TEST(s2 == "123");

Formatting support is provided by the underlying std::stringstream. Consequently, the API heavily borrows formatting metaphors from this underlying component. One such metaphor is the manipulator represented by std::hex, std::dec, std::uppercase, std::scientific, etc.

The following code demonstrates how char and wchar_t strings can be read in the std::hex or std::dec format:

boost::cnv::cstream ccnv;
boost::cnv::wstream wcnv;

int v01 = convert<int>("  FF", ccnv(std::hex)(std::skipws)).value_or(0);
int v02 = convert<int>(L"  F", wcnv(std::hex)(std::skipws)).value_or(0);
int v03 = convert<int>("  FF", ccnv(std::dec)(std::skipws)).value_or(-5);
int v04 = convert<int>(L"  F", wcnv(std::dec)(std::skipws)).value_or(-5);

BOOST_TEST(v01 == 255); // "FF"
BOOST_TEST(v02 ==  15); // L"F"
BOOST_TEST(v03 ==  -5); // Failed to convert "FF" as decimal.
BOOST_TEST(v04 ==  -5); // Failed to convert L"F" as decimal.

For batch-processing it might be more efficient to configure the converter once:

ccnv(std::showbase)(std::uppercase)(std::hex);

BOOST_TEST(convert<string>(255, ccnv, "bad") == "0XFF");
BOOST_TEST(convert<string>( 15, ccnv, "bad") ==  "0XF");

An alternative (generic) formatting interface is currently being extended and explored:

namespace cnv = boost::cnv;
namespace arg = boost::cnv::parameter;

ccnv(arg::base = cnv::base::dec)
    (arg::uppercase = true)
    (arg::notation = cnv::notation::scientific);

is equivalent to the following std::manipulator-based variant:

ccnv(std::dec)(std::uppercase)(std::scientific);

using std::string;
using std::wstring;
using boost::convert;

The following example demonstrates the deployment of std::dec, std::oct std::hex manipulators:

boost::cnv::cstream ccnv;

BOOST_TEST(convert<int>( "11", ccnv(std::hex)).value_or(0) == 17); // 11(16) = 17(10)
BOOST_TEST(convert<int>( "11", ccnv(std::oct)).value_or(0) ==  9); // 11(8)  = 9(10)
BOOST_TEST(convert<int>( "11", ccnv(std::dec)).value_or(0) == 11);

BOOST_TEST(convert<string>( 18, ccnv(std::hex)).value_or("bad") == "12"); // 18(10) = 12(16)
BOOST_TEST(convert<string>( 10, ccnv(std::oct)).value_or("bad") == "12"); // 10(10) = 12(8)
BOOST_TEST(convert<string>( 12, ccnv(std::dec)).value_or("bad") == "12");
BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::oct)).value_or("bad") == "377");
BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::hex)).value_or("bad") ==  "ff");
BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::dec)).value_or("bad") == "255");

ccnv(std::showbase);

BOOST_TEST(convert<string>(18, ccnv(std::hex)).value_or("bad") == "0x12");
BOOST_TEST(convert<string>(10, ccnv(std::oct)).value_or("bad") ==  "012");

ccnv(std::uppercase);

BOOST_TEST(convert<string>(18, ccnv(std::hex)).value_or("bad") == "0X12");

A more generic interface is also supported:

namespace cnv = boost::cnv;
namespace arg = boost::cnv::parameter;

BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::hex)).value_or(0) == 17);
BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::oct)).value_or(0) ==  9);
BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::dec)).value_or(0) == 11);

boost::cnv::cstream cnv;

boost::optional<string> s01 = convert<string>(12, cnv(std::setw(4)));
boost::optional<string> s02 = convert<string>(12, cnv(std::setw(5))(std::setfill('*')));
boost::optional<string> s03 = convert<string>(12, cnv(std::setw(5))(std::setfill('*'))(std::left));

BOOST_TEST(s01 && s01.value() == "  12");  // Field width = 4.
BOOST_TEST(s02 && s02.value() == "***12"); // Field width = 5, filler = '*'.
BOOST_TEST(s03 && s03.value() == "12***"); // Field width = 5, filler = '*', left adjustment

It needs to be remembered that boost::cnv::stream converter uses std::stream as its underlying conversion engine. Consequently, formatting-related behavior are driven by the std::stream. Namely, after every operation is performed, the default field width is restored. The values of the fill character and the adjustment remain unchanged until they are modified explicitly.

// The fill and adjustment remain '*' and 'left'.
boost::optional<string> s11 = convert<string>(12, cnv(arg::width = 4));
boost::optional<string> s12 = convert<string>(12, cnv(arg::width = 5)
                                                     (arg::fill = ' ')
                                                     (arg::adjust = cnv::adjust::right));

BOOST_TEST(s11 && s11.value() == "12**");  // Field width was set to 4.
BOOST_TEST(s12 && s12.value() == "   12"); // Field width was set to 5 with the ' ' filler.

using std::string;
using std::wstring;
using boost::convert;

    boost::cnv::cstream    ccnv;
    char const* const cstr_good = "  123";
    char const* const  cstr_bad = "  123 "; // std::skipws only affects leading spaces.

    ccnv(std::skipws);        // Ignore leading whitespaces
//  ccnv(arg::skipws = true); // Ignore leading whitespaces. Alternative interface

    BOOST_TEST(convert<int>(cstr_good, ccnv).value_or(0) == 123);
    BOOST_TEST(convert<string>("  123", ccnv).value_or("bad") == "123");

    BOOST_TEST(!convert<int>(cstr_bad, ccnv));

    ccnv(std::noskipws);       // Do not ignore leading whitespaces
//  ccnv(arg::skipws = false); // Do not ignore leading whitespaces. Alternative interface

    // All conversions fail.
    BOOST_TEST(!convert<int>(cstr_good, ccnv));
    BOOST_TEST(!convert<int>( cstr_bad, ccnv));

using std::string;
using std::wstring;
using boost::convert;

BOOST_TEST(convert<string>( true, cnv(std::boolalpha)).value_or("bad") ==  "true");
BOOST_TEST(convert<string>(false, cnv(std::boolalpha)).value_or("bad") == "false");

BOOST_TEST(convert<bool>( "true", cnv(std::boolalpha)).value_or(false) ==  true);
BOOST_TEST(convert<bool>("false", cnv(std::boolalpha)).value_or( true) == false);

BOOST_TEST(convert<string>( true, cnv(std::noboolalpha)).value_or("bad") == "1");
BOOST_TEST(convert<string>(false, cnv(std::noboolalpha)).value_or("bad") == "0");

BOOST_TEST(convert<bool>("1", cnv(std::noboolalpha)).value_or(false) ==  true);
BOOST_TEST(convert<bool>("0", cnv(std::noboolalpha)).value_or( true) == false);


PrevUpHomeNext