I want to implement a C++ command line generic argument parser (also for fun). Existing popular argument parsers lack some functionalities.
- gflags: Does not support vector very well.
- getopt: C based, this is for without type.
I want a generic argument parser that can process arbitrary types, something like this:
class YourArgument {
vector<int> your_ints;
string my_str;
bool help;
};
YourArgument your_arg;
Argparse(your_arg, argv, argc); // A template
This Argparse
can process something like "./run --help --my_str string --your_ints 1 2 3 run.txt"
.
I find something like C++17 structure binding can enable such implementation. If we are able to add some getters for a class, then we can implement it as follows.
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);
}
The parser implementation itself is just a normal recursive tricks, which is not the part that I need suggestion. My question is that is there any way to generate the boilerplate with macro?
I have tried this implementation, the code roughly looks like this (not the exact code I used). However, it drastically lengthen my compile performance. I have lots of such classes to compile, and the structs are very long.
#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]; }\
Aucun commentaire:
Enregistrer un commentaire