From 556d9354915fb718c48fa7127fb114a6e673688a Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sun, 17 Nov 2019 02:07:40 -0600 Subject: [PATCH 1/5] Suppress MSVC warnings and a Codacy warning --- include/argparse.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index a56ae6e..d06ec35 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -561,11 +561,11 @@ private: tCompoundArgument[1] != '-') { ++it; for (size_t j = 1; j < tCompoundArgument.size(); j++) { - auto tCurrentArgument = std::string{'-', tCompoundArgument[j]}; - if (auto tIterator = mArgumentMap.find(tCurrentArgument); - tIterator != mArgumentMap.end()) { - auto tArgument = tIterator->second; - it = tArgument->consume(it, end, tCurrentArgument); + auto tHypotheticalArgument = std::string{'-', tCompoundArgument[j]}; + auto tIterator2 = mArgumentMap.find(tHypotheticalArgument); + if (tIterator2 != mArgumentMap.end()) { + auto tArgument = tIterator2->second; + it = tArgument->consume(it, end, tHypotheticalArgument); } else { throw std::runtime_error("Unknown argument"); } From 4c5ded8c849de94f3d2d2d6e6f4e6e0605d7e3be Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sun, 17 Nov 2019 18:55:52 -0600 Subject: [PATCH 2/5] Constrain Argument constructor better Without this change, std::allocator can construct Argument --- include/argparse.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index d06ec35..4498462 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -69,6 +69,11 @@ struct is_container< template static constexpr bool is_container_v = is_container::value; +template +struct is_string_like + : std::conjunction, + std::is_convertible> {}; + template using enable_if_container = std::enable_if_t, T>; @@ -115,8 +120,7 @@ public: template ...>, - int> = 0> + std::conjunction_v...>, int> = 0> explicit Argument(Args &&... args) : Argument({std::string(std::forward(args))...}, std::make_index_sequence{}) {} From 3177f544f56eab3d61ee99e6892382e3f01b6533 Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sun, 17 Nov 2019 19:11:09 -0600 Subject: [PATCH 3/5] Default value is not a container of std::any --- include/argparse.hpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 4498462..fe23527 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -340,22 +340,16 @@ private: */ template details::enable_if_container get() const { - using ValueType = typename CONTAINER::value_type; - CONTAINER tResult; if (!mValues.empty()) { + using ValueType = typename CONTAINER::value_type; + CONTAINER tResult; std::transform( std::begin(mValues), std::end(mValues), std::back_inserter(tResult), [](const auto &value) { return std::any_cast(value); }); return tResult; } if (mDefaultValue.has_value()) { - const auto &tDefaultValues = - std::any_cast(mDefaultValue); - std::transform(std::begin(tDefaultValues), std::end(tDefaultValues), - std::back_inserter(tResult), [](const auto &value) { - return std::any_cast(value); - }); - return tResult; + return std::any_cast(mDefaultValue); } throw std::logic_error("No value provided"); } From 93ddf85a7b8f77215dda84ad83f60cb3f56b9552 Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sun, 17 Nov 2019 20:05:25 -0600 Subject: [PATCH 4/5] Factor out any_cast_container --- include/argparse.hpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index fe23527..9321a93 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -341,12 +341,7 @@ private: template details::enable_if_container get() const { if (!mValues.empty()) { - using ValueType = typename CONTAINER::value_type; - CONTAINER tResult; - std::transform( - std::begin(mValues), std::end(mValues), std::back_inserter(tResult), - [](const auto &value) { return std::any_cast(value); }); - return tResult; + return any_cast_container(mValues); } if (mDefaultValue.has_value()) { return std::any_cast(mDefaultValue); @@ -354,6 +349,17 @@ private: throw std::logic_error("No value provided"); } + template + static auto any_cast_container(const std::vector &aOperand) -> T { + using ValueType = typename T::value_type; + + T tResult; + std::transform( + begin(aOperand), end(aOperand), std::back_inserter(tResult), + [](const auto &value) { return std::any_cast(value); }); + return tResult; + } + std::vector mNames; std::string mUsedName; std::string mHelp; From f7dae0d93d07b5845b1bd5e2347318eec8e1dc88 Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sun, 17 Nov 2019 20:16:52 -0600 Subject: [PATCH 5/5] Refactor some uses of SFINAE into constexpr-if --- include/argparse.hpp | 62 +++++++++++++------------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 9321a93..400718e 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -74,12 +74,6 @@ struct is_string_like : std::conjunction, std::is_convertible> {}; -template -using enable_if_container = std::enable_if_t, T>; - -template -using enable_if_not_container = std::enable_if_t, T>; - template constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, std::index_sequence) { @@ -266,28 +260,20 @@ public: } /* - * Entry point for template non-container types + * Compare to an argument value of known type * @throws std::logic_error in case of incompatible types */ - template - std::enable_if_t, bool> - operator==(const T &aRhs) const { - return get() == aRhs; - } - - /* - * Template specialization for containers - * @throws std::logic_error in case of incompatible types - */ - template - std::enable_if_t, bool> - operator==(const T &aRhs) const { - using ValueType = typename T::value_type; - auto tLhs = get(); - return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), - std::end(aRhs), [](const auto &lhs, const auto &rhs) { - return std::any_cast(lhs) == rhs; - }); + template bool operator==(const T &aRhs) const { + if constexpr (!details::is_container_v) { + return get() == aRhs; + } else { + using ValueType = typename T::value_type; + auto tLhs = get(); + return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), + std::end(aRhs), [](const auto &lhs, const auto &rhs) { + return std::any_cast(lhs) == rhs; + }); + } } private: @@ -321,12 +307,15 @@ private: } /* - * Getter for template non-container types + * Get argument value given a type * @throws std::logic_error in case of incompatible types */ - template details::enable_if_not_container get() const { + template T get() const { if (!mValues.empty()) { - return std::any_cast(mValues.front()); + if constexpr (details::is_container_v) + return any_cast_container(mValues); + else + return std::any_cast(mValues.front()); } if (mDefaultValue.has_value()) { return std::any_cast(mDefaultValue); @@ -334,21 +323,6 @@ private: throw std::logic_error("No value provided"); } - /* - * Getter for container types - * @throws std::logic_error in case of incompatible types - */ - template - details::enable_if_container get() const { - if (!mValues.empty()) { - return any_cast_container(mValues); - } - if (mDefaultValue.has_value()) { - return std::any_cast(mDefaultValue); - } - throw std::logic_error("No value provided"); - } - template static auto any_cast_container(const std::vector &aOperand) -> T { using ValueType = typename T::value_type;