How to solve "boost::bad_any_cast: failed conversion using boost::any_cast" when using boost program options?

You see the boost::bad_any_cast exception thrown from the po::variables_map because the two const char* argument overload of po::options_description_easy_init::operator() does not specify a po::value_semantic type, so converting it to a std::string will not work. If you want to convert the value to a std::string, and it is required for your application, use the required() value semantic.

#include <boost/program_options.hpp>
namespace po = boost::program_options;

int main (int argc, char *argv[])
{
    po::options_description config("Configuration");
    config.add_options()
                ("IPAddress,i", po::value<std::string>()->required(), "IP Address")
                ("Port,p", po::value<std::string>()->required(), "Port")
                ;

    try {
        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, config),vm);
        po::notify(vm);
        std::cout << "Values" << std::endl;

        const std::string address = vm["IPAddress"].as<std::string>();
        const std::string port = vm["Port"].as<std::string>();

        std::cout << "address: " << address << std::endl;
        std::cout << "port: " << port << std::endl;
    } catch ( const std::exception& e ) {
        std::cerr << e.what() << std::endl;
        return 1;
    }

    return 0;
}

Note the added catch block since parsing can (and will, as you have noticed) throw exceptions. Here is a sample session:

samm$ ./a.out
the option '--IPAddress' is required but missing
samm$ ./a.out --IPAddress 127.0.0.1
the option '--Port' is required but missing
samm$ ./a.out --IPAddress 127.0.0.1 --Port 5000
Values
address: 127.0.0.1
port: 5000
samm$ 

Here is an online demo showing the same behavior, courtesy of COmpile LInk RUn (coliru).


You need to declare the ip-address and port as strings when you add the options:

config.add_options()
    ("IPAddress,i", po::value<std::string>(), "IP Address")
    ("Port,p", po::value<std::string>(), "Port")
    ;

This same message can also occur if you are not handling optional arguments correctly.

Sam's solution nails required arguments and the OP's code suggests required - just mark them required. For optional inputs, the Boost PO tutorial gives us a template for checking if the option exists before converting it:

if(vm.count("address")) 
{
    const std::string address = vm["IPAddress"].as<std::string>();
    std::cout << "address: " << address << std::endl;
}
if(vm.count("port")) 
    const std::string port = vm["Port"].as<std::string>();
    std::cout << "port: " << port << std::endl;
}

My problem - I had copied/pasted and forgotten to align the if test with the usage!