10

在下面的代码中,我使用程序选项从命令行或文件中读取参数。此外,可以在运行时通过ConfigProxy::setConfig以编程方式设置选项

po::options_description desc("Allowed options");
desc.add_options()
    ...
    ("compression", po::value<int>(), "set compression level");

po::variables_map vm;

class ConfigProxy
{
     template< typename T>
     void setConfig( const std::string key, const T value ){
          ... // check if the key exists in variable map "vm"

          // key exists, set the value
          runtimeConfig[key] = po::variable_value( boost::any(value), false);
     }

     po::variable_value& operator[] (const std::string key) const{
          ...
          // if exists in runtimeConfig return the value in runtimeConfig
          // of type program_options::variable_value
          ...
          // else return value in variable map "vm"
     }

     std::map<std::string, boost::program_options::variable_value> runtimeConfig;
}

通过ConfigProxy,取回option值

if( vm.count("compression") ){
    int value = proxyConfig["compression"].as<int>();
    ...
}

但是,如果用户提供的“压缩”选项值类型错误,例如

configProxy.setConfig("compression", "12" );
...
int value = configProxy["compression"].as<int>(); // was set as string

然后抛出异常

what():  boost::bad_any_cast: failed conversion using boost::any_cast

该异常清楚地显示了类型转换问题。但是该消息似乎对用户找出导致错误的选项没有太大帮助。

有没有更好的方法来通知用户这种类型的错误,而不是抛出bad_any_cast异常?

- - - 编辑 - - - - - - - - - - - - -

感谢 Luc Danton 和 Tony,我发现了程序选项如何显示错误。

void validate(boost::any& v,
              const std::vector< std::basic_string<charT> >& xs,
              T*, long)
{
    validators::check_first_occurrence(v);
    std::basic_string<charT> s(validators::get_single_string(xs));
    try {
        v = any(lexical_cast<T>(s));
    }
    catch(const bad_lexical_cast&) {
        boost::throw_exception(invalid_option_value(s));
    }
}

我认为,通过实现逻辑,我可以摆脱 bad_any_cast 异常。

4

2 回答 2

4

你试过了吗?

("compression", po::value<int>(), "set compression level");

注意po::value<int>()。您在此处指定关联值的类型为int。当用户传递 Boost.ProgramOptions 无法转换的内容时int,程序将失败并显示错误消息:

error: in option 'compression': invalid option value

毕竟这是图书馆的角色之一。

您必须这样做vm["compression"].as<int>()原因是因为compression在函数调用(括号中的三元组)中指定了类型,这是运行时世界中的某些内容。这不能影响 的返回类型vm["compression"],所以它需要一些动态类型模拟。因此,boost::any_cast_failed当您查询未指定的类型时会出现异常。

于 2011-06-08T16:44:55.737 回答
2

你能不能不放这个:

if( vm.count("compression") ){
    int value = vm["compression"].as<int>();
    ...
}

在一个try catch块中,您捕获bad_any_castboost 抛出的异常被捕获,然后向您自己的用户显示一条消息,方法是抛出(撤回)您创建的类型的新异常或向std::cout.很大程度上取决于您的应用程序。

所以:

try {
    if( vm.count("compression") ){
        int value = vm["compression"].as<int>();
        ...
    }
}
catch(const boost::bad_any_cast& ex)
{
//rethrow exception of your own to show to the user or print msg to std::cout
}
于 2011-06-08T16:28:37.390 回答