diff --git a/include/argparse.hpp b/include/argparse.hpp index a56ae6e..400718e 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -70,10 +70,9 @@ template static constexpr bool is_container_v = is_container::value; template -using enable_if_container = std::enable_if_t, T>; - -template -using enable_if_not_container = std::enable_if_t, T>; +struct is_string_like + : std::conjunction, + std::is_convertible> {}; template constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, @@ -115,8 +114,7 @@ public: template ...>, - int> = 0> + std::conjunction_v...>, int> = 0> explicit Argument(Args &&... args) : Argument({std::string(std::forward(args))...}, std::make_index_sequence{}) {} @@ -262,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: @@ -317,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); @@ -330,30 +323,15 @@ 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 { - using ValueType = typename CONTAINER::value_type; - CONTAINER tResult; - if (!mValues.empty()) { - 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; - } - 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; @@ -561,11 +539,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"); }