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

后端 未结 4 1129
伪装坚强ぢ
伪装坚强ぢ 2021-01-01 16:40
//Using boost program options to read command line and config file data
    #include 
    using namespace std;
    using namespace b         


        
相关标签:
4条回答
  • 2021-01-01 17:11

    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")
        ;
    
    0 讨论(0)
  • 2021-01-01 17:11

    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!

    0 讨论(0)
  • 2021-01-01 17:26

    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).

    0 讨论(0)
  • 2021-01-01 17:29

    Not necessarily the same problem as this guy had but here's something that caught me:

    If you put your type in an anonymous namespace, there will be two classes with the same name but different instances and the casting will fail. For example:

    a.hpp:

    namespace {
    class MyClass {...};
    }
    

    b.cpp:

    #include "a.hpp"
    cli_options.add_options()("test", po::value<MyClass>(), "test desc");
    

    c.cpp:

    #include "a.hpp" // THIS WILL MAKE A DIFFERENT "MyClass"
    vm["test"].as<MyClass>();  // Fails at runtime.
    

    It fails because the MyClass in b.cpp and the one in c.cpp aren't the same class. Because of the anonymous namespace.

    Removing the anonymous namespace solves the problem.

    0 讨论(0)
提交回复
热议问题