diff options
author | Vito Gamberini <vito.gamberini@kitware.com> | 2024-06-29 03:07:44 (GMT) |
---|---|---|
committer | Vito Gamberini <vito.gamberini@kitware.com> | 2024-07-02 13:58:57 (GMT) |
commit | 5fc2bad16741bec72c11463d61d7612aa231fb0e (patch) | |
tree | d1614ee29bf543f493e963c943ef66393b5f3aff | |
parent | e0f9d81f099adfb0ec41c92dd8c359aa0f2ac60c (diff) | |
download | CMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.zip CMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.tar.gz CMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.tar.bz2 |
cmArgumentParser: Support binding with derived classes
-rw-r--r-- | Source/cmArgumentParser.h | 8 | ||||
-rw-r--r-- | Tests/CMakeLib/testArgumentParser.cxx | 89 |
2 files changed, 60 insertions, 37 deletions
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index b35d7f3..c479b27 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -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); diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 2647fef..88b62e5 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -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; |