invalid option value exception using boost program-options

5.2k Views Asked by At

I have a Visual Studio 2008 C++ application using boost v1.45.0 program-options.

I would like to be able to parse a command-line option that looks like this: foo.exe -x 1,2, 4-7 such that it produces a std::vector< int > with the values [1, 2, 4, 5, 6, 7]. So, I've written a custom validator:

typedef std::vector< int > IDList;

void validate( boost::any& v, const std::vector< std::string >& tokens, IDList*, int )
{
    // Never gets here
}

int _tmain( int argc, _TCHAR* argv[] )
{
    IDList test_case_ids;

    po::options_description desc( "Foo options" );
    desc.add_options()
        ("id,x", po::value< IDList >(), "Specify a single ID or a range of IDs as shown in the following command line: foo.exe -x10,12, 15-20")
    ;

    po::variables_map vm;

    try
    {
        po::store( po::parse_command_line( argc, argv, desc ), vm );
        po::notify( vm );
    }
    catch( const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
        std::cout << desc << std::endl;
        return 1;
    }

    return 0;
}

But, I never get to my custom validator code. I always get an exception in parse_command_line with the message: in option 'id': invalid option value.

What do I need to do to make this work as desired?

Thanks, PaulH

3

There are 3 best solutions below

1
On BEST ANSWER

The typedef std::vector<int> as a boost::program_options::value_semantic does not work the way you desire because a vector has a special meaning to the program options library:

The library provides special support for vectors -- it will be possible to specify the option several times, and all specified values will be collected in one vector.

which means a description like so

typedef std::vector< int > IDList;
po::options_description desc( "Foo options" );
desc.add_options()
    ("id,x", po::value< IDList >(), "list of IDs")
;

is coalesced into a single std::vector<int> given the following command line

a.out --id 1 --id 2 --id 3 --id 4

the result would be a std::vector with four elements. You need to define a specific type to use the custom validator, struct IDList is the correct approach.

3
On

The problem is the definition of IDList. If I change the definition to match the magic_number type used in the regex.cpp sample, it works.

struct IDList
{
public:
    std::vector< int > ids_;
    IDList( std::vector< int > ids ) : ids_( ids ) {}
};

I haven't investigated why a typedef is a problem for the framework, but this works.

-PaulH

1
On

You could try writing your own function to parse the command line options:

See here

You write your own parser function, e.g. reg_foo, and use it as follows:

variables_map vm;
store(command_line_parser(argc, argv).options(desc).extra_parser(reg_foo)
          .run(), vm);

See also the example code distributed with boost, in example/custom_syntax.cpp