I've been very excited about reflection so I built a small library to pass command line arguments
Basic example:
struct Args
{
std::string first_name;
int age;
bool active;
};
// ./program --first-name John --age 99 --active
const auto args = clap::parse<Args>(argc, argv);
assert(args.first_name == "John");
assert(args.age == 99);
assert(args.active);More interesting example:
struct Args
{
[[= clap::Description<"host to connect to">{}]]
std::string host = "localhost";
[[=clap::ShortName<'p'>{}]]
std::uint16_t port;
[[=clap::Env<"RETRY_COUNT">{}]]
std::uint32_t retry_count;
std::optional<std::string> log_file;
[[=clap::ShortName<'e'>{}]]
bool encrypted;
[[=clap::ShortName<'c'>{}]]
bool compressed;
[[=clap::ShortName<'h'>{}]]
bool hashed;
};
// ./program -p 8080 -ec
const auto args = clap::parse<Args>(argc, argv);
assert(args.host == "localhost");
assert(args.port == 8080);
assert(args.retry_count == std::stoul(std::getenv("RETRY_COUNT")));
assert(!args.log_file);
assert(args.encrypted);
assert(args.compressed);
assert(!args.hashed);The amount of code to handle this is actually quite minimal < 500 lines.
There's a few modern goodies that make this code work:
-
Reflection []
-
Contracts []
-
Annotations for Reflection []
-
constexpr exceptions []
I guess we don't know what "idiomatic" reflection usage is like yet, I'm interested to come back to this code in a years time and see what mistakes I made!
Link to the code:
Any feedback, queries, questions are welcome!