c++ 带模板的通用命令行参数解析器,需要实现建议

6tqwzwtp  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(165)

我想实现一个C++命令行通用参数解析器(也是为了好玩)。现有的流行参数解析器缺乏一些功能。

*gflags:不太支持向量。
*getopt:基于C,用于无类型。

我想要一个可以处理任意类型的泛型参数解析器,如下所示:

class YourArgument {
   vector<int> your_ints;
   string my_str;
   bool help;
};
YourArgument your_arg; 
Argparse(your_arg, argv, argc); // A template

这个Argparse可以处理类似"./run --help --my_str string --your_ints 1 2 3 run.txt"的东西。
我发现像C++17结构绑定这样的东西可以实现这样的实现。如果我们能够为一个类添加一些getter,那么我们可以如下实现它。

class YourArgument {
   vector<int> your_ints;
   string my_str;
   bool help;
   auto& get(integral_constant<int, 0>) { return your_ints; }
   auto& get(integral_constant<int, 1>) { return my_str; }
   auto& get(integral_constant<int, 2>) { return help; }
   const char* getstr(int i) {
       if (i == 0) return "your_ints";
       if (i == 1) return "my_str";
       if (i == 2) return "help";
   }
};

template <typename T>
void Argparse_impl(T& your_arg, const char **argv, int &argc, int &c) {
    // Common recursive implementation
    // Skipped here
    Argparse_impl<i+1>(your_arg, argv, argc, c);
}

template <typename T>
void Argparse(T& your_arg, const char **argv, int &argc) {
    int c = 0;
    while (c < argc) Argparse_impl<0>(your_arg, argv, argc, c);
}

解析器实现本身就是一个普通的递归技巧,这不是我需要建议的部分。我的问题是有没有办法用宏生成样板?
我试过这个实现,代码大致看起来像这样(不是我使用的确切代码)。然而,它大大延长了我的编译性能。我有很多这样的类要编译,结构体非常长。

#define MY_MACRO(...)\
    auto& get_tuple() { return forward_as_tuple(__VA_ARGS_); }\
    template<unsigned i> auto& get() { return get<i>(get_tuple()); }\
    const char* getstr() { static string strs = string(##__VA_ARGS_).split(); return strs[i]; }\
gwbalxhn

gwbalxhn1#

虽然我恐怕我没有一个关于如何改进你的解决方案的建议,但似乎你正在寻找的功能是完全可能的,而不使用宏的使用C++ argparse库https://github.com/morrisfranken/argparse。它支持向量,一切都表示在一个结构中。这里是一个例子,你可以如何使用它为你的例子

#include "argparse/argparse.hpp"

struct MyArgs : public argparse::Args {
    std::string &src_path     = arg("a positional string argument");
    int &k                    = kwarg("k", "A keyworded integer value");
    std::vector<int> &numbers = kwarg("n,numbers", "An optional vector of integers").multi_argument().set_default(std::vector<int>{1,2});
    bool &verbose             = flag("v,verbose", "A flag to toggle verbose");
};

int main(int argc, char* argv[]) {
    MyArgs args = argparse::parse<MyArgs>(argc, argv);

    // print all input numbers
    for (int &n : args.numbers)
         std::cout << n << std::endl;

    return 0;
}

您可以使用以下命令运行此示例:

./run source_path -k 1 --numbers 3 4 5

免责声明:我是图书馆的作者

相关问题