3

I am trying to use a custom validator instead of overloading operator>> to support an enum type in my option parsing. I have done the following:

#include <iostream>

#include <boost/program_options.hpp>

enum class MyEnum
{
    OneThing,
    AnotherThing
};

void validate(boost::any& v, const std::vector<std::string>& values,
              MyEnum*, int)
{
    // parse the enum from values[0]
    std::cout << "Test" << std::endl;
    MyEnum enumValue = MyEnum::OneThing;
    v = enumValue;
}

int main(int argc, char*argv[])
{
    namespace po = boost::program_options;

    po::options_description desc("Options");

    //desc.add_options()("myEnum", po::value<MyEnum>(), "MyEnum value"); // works fine
    desc.add_options()("myEnum", po::value<MyEnum>()->default_value(MyEnum::OneThing), "MyEnum value"); // compiler error: Source type is not streamable

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    MyEnum myEnum = vm["myEnum"].as<MyEnum>();

    return 0;
}

This works fine as long as I don't try to set a default_value, but when I do specify a default_value, I get error: static assertion failed: Source type is neither std::ostream able nor std::wostream able. What else do I need (without overloading stream operators, which is the whole point of using a validator as far as I understand) to do to allow a custom type to get a default_value?

David Doria
  • 9,873
  • 17
  • 85
  • 147

1 Answers1

4

You can set a default value, however, it needs to know how to represent the default value in the descriptions.

Since the enum isn't streamable, the automatic way doesn't work, so you must specify it, e.g.:

default_value(MyEnum::OneThing, "OneThing")

Live On Coliru

#include <iostream>

#include <boost/program_options.hpp>

enum class MyEnum
{
    OneThing,
    AnotherThing
};

void validate(boost::any& v, const std::vector<std::string>& values,
              MyEnum*, int)
{
    // parse the enum from values[0]
    std::cout << "Test" << std::endl;
    MyEnum enumValue = MyEnum::OneThing;
    v = enumValue;
}

int main(int argc, char*argv[])
{
    namespace po = boost::program_options;

    po::options_description desc("Options");

    //desc.add_options()("myEnum", po::value<MyEnum>(), "MyEnum value"); // works fine
    desc.add_options()("myEnum", po::value<MyEnum>()->default_value(MyEnum::OneThing, "OneThing"), "MyEnum value");

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    MyEnum myEnum = vm["myEnum"].as<MyEnum>();
    std::cout << std::boolalpha << (myEnum == MyEnum::OneThing) << "\n";
}

Prints

true
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Strange, I would have thought the actual value of the default was stored in the options, not the string that would produce the value. It works though, cheers. – David Doria Mar 08 '16 at 14:31
  • 2
    If you read carefully, you'll note that I'm not saying otherwise. I **did** explain why you need to have the textual representation though. So maybe you want to read it again :) – sehe Mar 08 '16 at 14:32