Search code examples
c++boostboost-program-options

How to overload operator<< for use with boost::program_options default value output?


I am using boost::program_options and want to pass "domain"-like options to my program. Such a domain is simply:

template<typename T>
struct CDomain
{
  CDomain(T min = -1, T max = 1) {_min = min; _max = max;};
  T _min;
  T _max;
};

I have written a custom validator for this option class and that works well. Now as I wanted to add a default value, as in

desc.add_options()("domain", po::value<CDomain<long double> >()->default_value(CDomain<long double>(-1,1)), "domain");

boost::program_options called for an operator<<:

error: no match for ‘operator<<’ in ‘stream << input’

I added this one, but still get the same error message:

template<typename T>
ostream& operator<<(ostream& o, CDomain<T>& d)
{
  return o << "[" << boost::lexical_cast<string>(d._min) << ":" << boost::lexical_cast<string>(d._max) << "]";
}

How can I define operator<< for use with default value output in custom option descriptions?


I did some more investigation. The error occurs in boost/lexical_cast.hpp:1147 In member function bool boost::detail::lexical_stream_limited_src<CharT, Traits, RequiresStringbuffer>::shl_input_streamable(InputStreamable&) [with InputStreamable = const CDomain<long double>, CharT = char, Traits = std::char_traits<char>, bool RequiresStringbuffer = true]:

template<typename InputStreamable>
bool shl_input_streamable(InputStreamable& input)
{
    std::basic_ostream<CharT> stream(&stringbuffer);
    bool const result = !(stream << input).fail();
    start = stringbuffer.pbase();
    finish = stringbuffer.pptr();
    return result && (start != finish);
}

This might be a namespace issue, but moving ostream& operator<<(ostream& o, CDomain<T>& d) into boost::detail didn't solve the problem.


Solution

  • Redefine your structure likewise:

    template<typename T>
    struct CDomain
    {
      CDomain(T min = -1, T max = 1) {_min = min; _max = max;};
      T _min;
      T _max;
    
      friend std::ostream& operator << (std::ostream& s, const CDomain& domain)
      {
        so << "[" << boost::lexical_cast<string>(d._min) << ":" << boost::lexical_cast<string>(d._max) << "]"
        return s;
      }
    };
    

    That should fix the issue I believe. Here I see it working (Modifed version to make it work online).