cmArgumentParser: Support binding with derived classes

This commit is contained in:
Vito Gamberini
2024-06-28 23:07:44 -04:00
parent e0f9d81f09
commit 5fc2bad167
2 changed files with 60 additions and 37 deletions

View File

@@ -17,6 +17,7 @@
#include <cm/string_view>
#include <cm/type_traits>
#include <cmext/string_view>
#include <cmext/type_traits>
#include "cmArgumentParserTypes.h" // IWYU pragma: keep
@@ -244,8 +245,11 @@ class cmArgumentParser : private ArgumentParser::Base
public:
// I *think* this function could be made `constexpr` when the code is
// compiled as C++20. This would allow building a parser at compile time.
template <typename T>
cmArgumentParser& Bind(cm::static_string_view name, T Result::*member)
template <typename T, typename cT = cm::member_pointer_class_t<T>,
typename mT = cm::remove_member_pointer_t<T>,
typename = cm::enable_if_t<std::is_base_of<cT, Result>::value>,
typename = cm::enable_if_t<!std::is_function<mT>::value>>
cmArgumentParser& Bind(cm::static_string_view name, T member)
{
this->Base::Bind(name, [member](Instance& instance) {
instance.Bind(static_cast<Result*>(instance.Result)->*member);

View File

@@ -97,6 +97,10 @@ struct Result : public ArgumentParser::ParseResult
std::vector<cm::string_view> ParsedKeywords;
};
struct Derived : Result
{
};
std::initializer_list<cm::string_view> const args = {
/* clang-format off */
"pos0", // position index 0
@@ -312,41 +316,44 @@ static auto const parserStaticFunc4 =
cm::string_view arg) -> ArgumentParser::Continue {
return result.Func4(key, arg);
};
static auto const parserStatic = //
cmArgumentParser<Result>{}
.Bind(0, &Result::Pos0)
.Bind(1, &Result::Pos1)
.Bind(2, &Result::Pos2)
.Bind("OPTION_1"_s, &Result::Option1)
.Bind("OPTION_2"_s, &Result::Option2)
.Bind("STRING_1"_s, &Result::String1)
.Bind("STRING_2"_s, &Result::String2)
.Bind("STRING_3"_s, &Result::String3)
.Bind("STRING_4"_s, &Result::String4)
.Bind("STRING_5"_s, &Result::String5)
.Bind("STRING_6"_s, &Result::String6)
.Bind("LIST_1"_s, &Result::List1)
.Bind("LIST_2"_s, &Result::List2)
.Bind("LIST_3"_s, &Result::List3)
.Bind("LIST_4"_s, &Result::List4)
.Bind("LIST_5"_s, &Result::List5)
.Bind("LIST_6"_s, &Result::List6)
.Bind("MULTI_1"_s, &Result::Multi1)
.Bind("MULTI_2"_s, &Result::Multi2)
.Bind("MULTI_3"_s, &Result::Multi3)
.Bind("MULTI_4"_s, &Result::Multi4)
.Bind("FUNC_0"_s, &Result::Func0)
.Bind("FUNC_1"_s, &Result::Func1)
.Bind("FUNC_2a"_s, &Result::Func2)
.Bind("FUNC_2b"_s, &Result::Func2)
.Bind("FUNC_3"_s,
[](Result& result, cm::string_view arg) -> ArgumentParser::Continue {
return result.Func3(arg);
})
.Bind("FUNC_4a"_s, parserStaticFunc4)
.Bind("FUNC_4b"_s, parserStaticFunc4)
.BindParsedKeywords(&Result::ParsedKeywords)
/* keep semicolon on own line */;
#define BIND_ALL(name, resultType) \
static auto const name = \
cmArgumentParser<resultType>{} \
.Bind(0, &resultType::Pos0) \
.Bind(1, &resultType::Pos1) \
.Bind(2, &resultType::Pos2) \
.Bind("OPTION_1"_s, &resultType::Option1) \
.Bind("OPTION_2"_s, &resultType::Option2) \
.Bind("STRING_1"_s, &resultType::String1) \
.Bind("STRING_2"_s, &resultType::String2) \
.Bind("STRING_3"_s, &resultType::String3) \
.Bind("STRING_4"_s, &resultType::String4) \
.Bind("STRING_5"_s, &resultType::String5) \
.Bind("STRING_6"_s, &resultType::String6) \
.Bind("LIST_1"_s, &resultType::List1) \
.Bind("LIST_2"_s, &resultType::List2) \
.Bind("LIST_3"_s, &resultType::List3) \
.Bind("LIST_4"_s, &resultType::List4) \
.Bind("LIST_5"_s, &resultType::List5) \
.Bind("LIST_6"_s, &resultType::List6) \
.Bind("MULTI_1"_s, &resultType::Multi1) \
.Bind("MULTI_2"_s, &resultType::Multi2) \
.Bind("MULTI_3"_s, &resultType::Multi3) \
.Bind("MULTI_4"_s, &resultType::Multi4) \
.Bind("FUNC_0"_s, &resultType::Func0) \
.Bind("FUNC_1"_s, &resultType::Func1) \
.Bind("FUNC_2a"_s, &resultType::Func2) \
.Bind("FUNC_2b"_s, &resultType::Func2) \
.Bind("FUNC_3"_s, \
[](resultType& result, cm::string_view arg) \
-> ArgumentParser::Continue { return result.Func3(arg); }) \
.Bind("FUNC_4a"_s, parserStaticFunc4) \
.Bind("FUNC_4b"_s, parserStaticFunc4) \
.BindParsedKeywords(&resultType::ParsedKeywords)
BIND_ALL(parserStatic, Result);
BIND_ALL(parserDerivedStatic, Derived);
bool testArgumentParserStatic()
{
@@ -355,6 +362,13 @@ bool testArgumentParserStatic()
return verifyResult(result, unparsedArguments);
}
bool testArgumentParserDerivedStatic()
{
std::vector<std::string> unparsedArguments;
Derived const result = parserDerivedStatic.Parse(args, &unparsedArguments);
return verifyResult(result, unparsedArguments);
}
bool testArgumentParserStaticBool()
{
std::vector<std::string> unparsedArguments;
@@ -377,6 +391,11 @@ int testArgumentParser(int /*unused*/, char* /*unused*/[])
return -1;
}
if (!testArgumentParserDerivedStatic()) {
std::cout << "While executing testArgumentParserDerivedStatic().\n";
return -1;
}
if (!testArgumentParserStaticBool()) {
std::cout << "While executing testArgumentParserStaticBool().\n";
return -1;