Как решить "boost:: bad_any_cast: неудачное преобразование с использованием boost:: any_cast" при использовании опций форматирования?

//Using boost program options to read command line and config file data
    #include <boost/program_options.hpp>
    using namespace std;
    using namespace boost;
    namespace po = boost::program_options;

int main (int argc, char *argv[])
{
    po::options_description config("Configuration");
    config.add_options()
                ("IPAddress,i","IP Address")
                ("Port,p","Port")
                 ;

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

    cout << "Values\n";

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

    cout << (vm["IPAddress"].as< string >()).c_str();
    cout << " " << (vm["Port"].as<string>()).c_str();

    return 0;

}

Являются ли введенные значения некорректными?

Вот вывод gdb, кажется, проблема с литьем:

завершение вызова после вызова экземпляра "Повышение:: exception_detail:: clone_impl

"                 what(): boost:: bad_any_cast: неудачное преобразование с использованием boost:: any_cast

        Program received signal SIGABRT, Aborted.
        0x0000003afd835935 in raise () from /lib64/libc.so.6
string address = (vm["IPAddress"].as<std::string >()).c_str();

возникает ошибка; Я пробовал std::string и строку с теми же результатами.

testboostpo -i 192.168.1.10 -p 5000

- это командная строка.

Я попробовал объявить типы, например:

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

но ошибка все же произошла.

Может ли это быть настоящей ошибкой?

Ответ 1

Вы видите исключение boost::bad_any_cast, выведенное из po::variables_map, потому что две перегрузки аргумента const char* po::options_description_easy_init::operator() не указывают a po::value_semantic, поэтому преобразование его в std::string не будет работать. Если вы хотите преобразовать значение в std::string, и оно требуется для вашего приложения, используйте семантическое значение required().

#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;
}

Обратите внимание на добавленный блок catch, поскольку синтаксический анализ может (и будет, как вы заметили) отбрасывать исключения. Вот пример сеанса:

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$ 

Вот онлайн-демонстрация, демонстрирующая такое же поведение, любезно предоставленное COmpile LInk RUn (coliru).

Ответ 2

Вам нужно объявить ip-адрес и порт как строки при добавлении опций:

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

Ответ 3

Это же сообщение также может возникнуть, если вы неправильно обрабатываете необязательные аргументы.

Сэм должен найти необходимые аргументы и указать код OP - просто отметьте их. Для дополнительных входов учебник Boost PO дает нам шаблон для проверки наличия опциона перед его преобразованием:

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;
}

Моя проблема - я скопировал/вставил и забыл выровнять тест if с использованием!