summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVito Gamberini <vito.gamberini@kitware.com>2024-06-29 03:07:44 (GMT)
committerVito Gamberini <vito.gamberini@kitware.com>2024-07-02 13:58:57 (GMT)
commit5fc2bad16741bec72c11463d61d7612aa231fb0e (patch)
treed1614ee29bf543f493e963c943ef66393b5f3aff
parente0f9d81f099adfb0ec41c92dd8c359aa0f2ac60c (diff)
downloadCMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.zip
CMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.tar.gz
CMake-5fc2bad16741bec72c11463d61d7612aa231fb0e.tar.bz2
cmArgumentParser: Support binding with derived classes
-rw-r--r--Source/cmArgumentParser.h8
-rw-r--r--Tests/CMakeLib/testArgumentParser.cxx89
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;