Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit the precision on std::cout of default values in boost::options_description

When I construct a boost::options_description instance like

options.add_options()
  ("double_val", value(&config.my_double)->default_value(0.2), "it's a double");

and later want to have the automated output of the options that are available for my program, and put

std::cout << options << std::endl;

the default value 0.2 is shown with way too high precision, which effectively clutters my output when I have long variable names:

--double_val (=0.20000000000000001) it's a double

unfortunately, a prior call to std::cout.precision did not help:

cout.precision(5);
std::cout << options << std::endl;

this leads still to the same output :/

Do you have any ideas on how to limit the display of the default value to less positions?

Best regards, Christian

like image 312
Christian Avatar asked Nov 14 '09 17:11

Christian


1 Answers

From boost/program_options/value_semantic.hpp:

    /** Specifies default value, which will be used
        if none is explicitly specified. The type 'T' should
        provide operator<< for ostream.
    */
    typed_value* default_value(const T& v)
    {
        m_default_value = boost::any(v);
        m_default_value_as_text = boost::lexical_cast<std::string>(v);
        return this;
    }

    /** Specifies default value, which will be used
        if none is explicitly specified. Unlike the above overload,
        the type 'T' need not provide operator<< for ostream,
        but textual representation of default value must be provided
        by the user.
    */
    typed_value* default_value(const T& v, const std::string& textual)
    {
        m_default_value = boost::any(v);
        m_default_value_as_text = textual;
        return this;
    }

So the implementation is dead simple (never a sure thing with Boost!). Trying to reconfigure your ostream to make the formatting come out as you want won't work, because the default value just gets converted to a string in a standalone ostringstream (inside lexical_cast).

So a simple workaround is to add your desired string representation as a second argument to default_value. Then you can make it print however you want (including not at all, if you pass an empty string). Like so:

value(&config.my_double)->default_value(0.2, "0.2")

The more "enterprisey" way to accomplish the same thing would be to implement your own type which would wrap double, be used for config.my_double, and provide construction from and coercion to double, and your very own ostream& operator<< with exactly the formatting you desire. I don't suggest this approach, however, unless you're writing a library that demands generality.

From the Boost Lexical Cast notes:

The previous version of lexical_cast used the default stream precision for reading and writing floating-point numbers. For numerics that have a corresponding specialization of std::numeric_limits, the current version now chooses a precision to match.

like image 180
John Zwinck Avatar answered Oct 19 '22 08:10

John Zwinck