Search code examples
c++boostboost-program-options

`boost::program_options` cannot use `store` twice on `variables_map`


I'm trying to edit a boost::program_options::variables_map to add implied option according to the first positional option. However, using po::store doesn't work a second time when using it on a boost::variables_map.

Here is a minimal example that fails :

#include <boost/program_options.hpp>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>

namespace po = boost::program_options;

std::ostream &operator<<( std::ostream &s, po::variables_map const &vm )
{
    for (const auto& it : vm)
    {
        s << it.first.c_str() << " ";
        auto& value = it.second.value();
        if (auto v = boost::any_cast<char>(&value))
            s << *v;
        else if (auto v = boost::any_cast<short>(&value))
            s << *v;
        else if (auto v = boost::any_cast<int>(&value))
            s << *v;
        else if (auto v = boost::any_cast<long>(&value))
            s << *v;
        else if (auto v = boost::any_cast<std::string>(&value))
            s << *v;
        else if (auto v = boost::any_cast<std::vector<std::string>>(&value))
        {
            s << "[";
            for( const auto &w : *v )
                s << " " << w;
            s << " ]";
        }
        else
            s << "<?>";
        s << '\n';
    }
    return s;
}

int main( int argc, char **argv )
{
    po::options_description  desc("Options");
    desc.add_options()
        ("help","show this help message")
        ("verbose","print extra messages")
        ("dummy","pointless")
        ("dummy-int", po::value< int >(), "pointless")
        ("dummy-str", po::value< std::string >(), "pointless")
    ;

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

    bool verbose = vm.count("verbose");

    if( verbose )
        std::cout << vm << std::endl;

    if( vm.count( "help" ) )
    {
        std::cout << desc << std::endl;
        return 0;
    }

    const char* newOption = "--dummy";
    po::store( po::parse_command_line( 1, &newOption, desc), vm );
    po::notify( vm );

    if( verbose )
        std::cout << vm << std::endl;

    return 0;
}

Building and running the program, I can see on the terminal :

dummy-int 3
verbose 

dummy-int 3
verbose 

In other words, option dummy was not stored into vm ! Can you help me find why not ? Thank you for any help !


Solution

  • You forgot that the first argument has a special meaning -- it is the name of the program as it was invoked.

    According to the documentation:

    argv[0] is the pointer to the initial character of a null-terminated multibyte strings that represents the name used to invoke the program itself (or an empty string "" if this is not supported by the execution environment).

    In the snippet

    const char* newOption = "--dummy";
    po::store( po::parse_command_line( 1, &newOption, desc), vm );
    

    You pass a one element array as argv, which means you're not supplying any arguments, and there's nothing for the library to parse. Hence, nothing is added to the variable_map instance.