web-dev-qa-db-ja.com

ブーストプログラムオプションを使用するときに「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の出力で、キャストの問題のようです。

'boost :: 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と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");

しかし、それでもエラーは発生しました。

これは本物のバグでしょうか?

16
bentaisan

po::options_description_easy_init::operator() の2つのboost::bad_any_cast引数のオーバーロードがpo::variables_mapタイプを指定していないため、const char*からスローされた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$ 

これが オンラインデモ 同じ動作を示しています。COmpileLInkRUn(coliru)の好意によるものです。

15
Sam Miller

オプションを追加するときは、IPアドレスとポートを文字列として宣言する必要があります。

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

これと同じメッセージは、オプションの引数を正しく処理していない場合にも発生する可能性があります。

サムのソリューションは必須の引数を釘付けにし、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テストを使用法に合わせるのを忘れていました!

2
sage