我的程序有一组可能发生的可恢复错误,我们称它们为ErrorA
、ErrorB
和ErrorC
。对于这些错误中的任何一个,我的程序可以忽略它们(因为它们是可恢复的(,也可以终止,后者是默认行为。现在,我希望用户指定是否应该忽略这些错误。这应该通过命令行参数--ignore
来实现,后面跟着应忽略的错误名称。例如:
./MyProgram --ignore ErrorA ErrorC
在代码中,我使用单个位掩码枚举表示这些错误类别:
enum class IgnoreErrors {
None = 0, //Ignore no errors
ErrorA = 1 << 0,
ErrorB = 1 << 1,
ErrorC = 1 << 2
};
我正在使用boost::program_options
,并试图将--ignore
选项添加到options_description
中,如下所示:
value<IgnoreErrors>()->multitoken()->default_value(IgnoreErrors::None)
这需要我为IgnoreErrors
提供一个operator>>
的实现,而这正是我陷入困境的地方。我试过这个:
istream& operator>>(istream& in, IgnoreErrors& err) {
//Assumption: 'in' contains ALL tokens passed to the --ignore flag
err = IgnoreErrors::None; //Needed to make |= work
string token;
while(getline(in, token, ' ')) {
err |= ignore_error_from_str(token);
}
return in;
}
这将正确地将一个或多个令牌解析为一个IgnoreErrors
值,但之后我的程序将失败:the argument ('ErrorA ErrorC') for option '--ignore' is invalid
。有趣的是,如果我使用in >> token
而不是getline
,我只会得到第一个令牌(ErrorA
(。
如果我将operator>>
的实现更改为将单个令牌解析为单个IgnoreError
值,并将options_description
更改为使用value<vector<IgnoreErrors>>()
,Boost将不再识别IgnoreErrors
的operator>>
,而是查找vector<IgnoreErrors>
的实现。然而,我必须手动将这个向量折叠成一个单独的IgnoreErrors
值,这似乎很奇怪。我想了解处理这种情况的"预期"方式是什么。
如何使用boost::program_options
将多令牌参数解析为单个值?
所以我找到了一种合理的方法来完成这项工作。可以使用自定义验证器,而不是提供operator>>
,如下所示:
void validate(boost::any &v, const std::vector<std::string> &all_tokens,
IgnoreErrors *target_type, int) {
validators::check_first_occurrence(v);
std::vector<std::string> tokens;
boost::algorithm::split(tokens,
validators::get_single_string(all_tokens),
boost::is_any_of(" "));
auto ignore_errors = IgnoreErrors::None;
for (auto &token : tokens) {
ignore_errors |= ignore_error_from_str(token);
}
v = boost::any(ignore_errors);
}
有些事情对我来说并不那么明显:
- 在我的例子中,
validators::get_single_string(all_tokens)
的结果是"ErrorA ErrorC"
,所以我不得不手动将这个字符串拆分为多个令牌 validate
函数的专用化必须与它专用的类型(在我的例子中为IgnoreErrors
(在同一个命名空间中