【问题标题】:boost::program_options validation per argument instead of per argument type?boost::program_options 验证每个参数而不是每个参数类型?
【发布时间】:2017-07-30 14:58:46
【问题描述】:

boost::program_options 似乎支持某种程度的custom validation,但我觉得奇怪的是,验证是根据类型而不是按参数编写的,我想知道我是否在这里遗漏了什么。

例如,假设您有一个“文件编辑”程序,它从命令行获取 inputoutput 文件名。接下来假设您要将这些存储到boost::filesystem::path 类型的变量中。现在,假设我们要求input 文件必须 存在,但output 文件不存在(即如果output 文件不存在,我们将创建它。)理想情况下,我们有一种方法来测试input 参数是否存在,以及output 文件是否存在并且是可写的,或者位于我们可以写入的目录中。 (这里的具体差异实际上并不相关。这适用于您在多个地方使用相同类型的任何情况,您希望根据使用情况有不同的验证规则。)

因为我们通过创建 validate 的覆盖来配置验证器(可能在编译时通过它们的类型签名找到,看来我们只能为 boost::filesystem::path 的所有实例设置一个验证器。我见过 @987654333 @hook,但是这些回调的签名具有 const 限定符,因此您似乎无法修改该值,并且在文档中尚不清楚 throwing 在 notify 回调中如何工作进入验证系统。

这似乎是一个非常基本的限制,以至于我认为我可能遗漏了一些东西。我是吗?想法?

【问题讨论】:

  • 你可以将你的参数包装成它自己的类型。
  • 这比听起来要难。例如, boost::filesystem::path 有许多构造函数可以手动为其编写传递。我尝试使用 C++11 构造函数继承,但该功能与 boost::program_options 中的各种元编程之间似乎存在一些根本的不兼容。抽象地说,将有效的特定于上下文的运行时复杂性(即我使用 program_options 的复杂性,而不是它的功能)强加到类型系统上也是错误的。
  • 除了默认的,不需要实现构造函数。包装器类型仅用于进行转换,不应在参数处理代码之外使用(外部代码应接收基类型)。

标签: c++ boost-program-options


【解决方案1】:

在程序中为每个概念设置一种类型永远不会有什么坏处。如果两条路径代表不同的概念,请给它们自己的类型:

#include <iostream>
#include <cstdlib>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>

namespace po = boost::program_options;
namespace fs = boost::filesystem;

template<class Type, class Tag>
struct tagged
{
    Type const& get() const { return value_; }
    Type& get() { return value_; }
    operator Type& () { get(); }

    friend decltype(auto) operator>>(std::istream& is, tagged& t) {
        return is >> t.get();
    }

    friend decltype(auto) operator<<(std::ostream& os, tagged const& t) {
        return os << t.get();
    }

    // and so on...

    Type value_;
};

using bar_path = tagged<fs::path, class bar_path_tag>;
using foo_path = tagged<fs::path, class foo_path_tag>;

int main()
{
    bar_path bar;
    foo_path foo;

    po::options_description desc("prog");
    desc.add_options()
    ("foo", po::value(&foo), "a foo path")
    ("bar", po::value(&bar), "a bar path")
    ;
}

【讨论】:

    【解决方案2】:

    您可以将每个选项的验证逻辑放入 notifier 回调中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-02
      • 2018-12-10
      • 1970-01-01
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多