Merge pull request #54 from lichray/less-sfinae

Finishing cleanup by refactoring SFINAE into constexpr-if
This commit is contained in:
Pranav Srinivas Kumar 2019-11-17 22:17:13 -06:00 committed by GitHub
commit 6ee8de5f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -70,10 +70,9 @@ template <typename T>
static constexpr bool is_container_v = is_container<T>::value; static constexpr bool is_container_v = is_container<T>::value;
template <typename T> template <typename T>
using enable_if_container = std::enable_if_t<is_container_v<T>, T>; struct is_string_like
: std::conjunction<std::is_constructible<std::string, T>,
template <typename T> std::is_convertible<T, std::string_view>> {};
using enable_if_not_container = std::enable_if_t<!is_container_v<T>, T>;
template <class F, class Tuple, class Extra, size_t... I> template <class F, class Tuple, class Extra, size_t... I>
constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, constexpr decltype(auto) apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x,
@ -115,8 +114,7 @@ public:
template <typename... Args, template <typename... Args,
std::enable_if_t< std::enable_if_t<
std::conjunction_v<std::is_constructible<std::string, Args>...>, std::conjunction_v<details::is_string_like<Args>...>, int> = 0>
int> = 0>
explicit Argument(Args &&... args) explicit Argument(Args &&... args)
: Argument({std::string(std::forward<Args>(args))...}, : Argument({std::string(std::forward<Args>(args))...},
std::make_index_sequence<sizeof...(Args)>{}) {} std::make_index_sequence<sizeof...(Args)>{}) {}
@ -262,22 +260,13 @@ 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 * @throws std::logic_error in case of incompatible types
*/ */
template <typename T> template <typename T> bool operator==(const T &aRhs) const {
std::enable_if_t<!details::is_container_v<T>, bool> if constexpr (!details::is_container_v<T>) {
operator==(const T &aRhs) const {
return get<T>() == aRhs; return get<T>() == aRhs;
} } else {
/*
* Template specialization for containers
* @throws std::logic_error in case of incompatible types
*/
template <typename T>
std::enable_if_t<details::is_container_v<T>, bool>
operator==(const T &aRhs) const {
using ValueType = typename T::value_type; using ValueType = typename T::value_type;
auto tLhs = get<T>(); auto tLhs = get<T>();
return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs), return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs),
@ -285,6 +274,7 @@ public:
return std::any_cast<const ValueType &>(lhs) == rhs; return std::any_cast<const ValueType &>(lhs) == rhs;
}); });
} }
}
private: private:
static bool is_integer(const std::string &aValue) { static bool is_integer(const std::string &aValue) {
@ -317,11 +307,14 @@ private:
} }
/* /*
* Getter for template non-container types * Get argument value given a type
* @throws std::logic_error in case of incompatible types * @throws std::logic_error in case of incompatible types
*/ */
template <typename T> details::enable_if_not_container<T> get() const { template <typename T> T get() const {
if (!mValues.empty()) { if (!mValues.empty()) {
if constexpr (details::is_container_v<T>)
return any_cast_container<T>(mValues);
else
return std::any_cast<T>(mValues.front()); return std::any_cast<T>(mValues.front());
} }
if (mDefaultValue.has_value()) { if (mDefaultValue.has_value()) {
@ -330,31 +323,16 @@ private:
throw std::logic_error("No value provided"); throw std::logic_error("No value provided");
} }
/* template <typename T>
* Getter for container types static auto any_cast_container(const std::vector<std::any> &aOperand) -> T {
* @throws std::logic_error in case of incompatible types using ValueType = typename T::value_type;
*/
template <typename CONTAINER> T tResult;
details::enable_if_container<CONTAINER> get() const {
using ValueType = typename CONTAINER::value_type;
CONTAINER tResult;
if (!mValues.empty()) {
std::transform( std::transform(
std::begin(mValues), std::end(mValues), std::back_inserter(tResult), begin(aOperand), end(aOperand), std::back_inserter(tResult),
[](const auto &value) { return std::any_cast<ValueType>(value); }); [](const auto &value) { return std::any_cast<ValueType>(value); });
return tResult; return tResult;
} }
if (mDefaultValue.has_value()) {
const auto &tDefaultValues =
std::any_cast<const CONTAINER &>(mDefaultValue);
std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
std::back_inserter(tResult), [](const auto &value) {
return std::any_cast<ValueType>(value);
});
return tResult;
}
throw std::logic_error("No value provided");
}
std::vector<std::string> mNames; std::vector<std::string> mNames;
std::string mUsedName; std::string mUsedName;
@ -561,11 +539,11 @@ private:
tCompoundArgument[1] != '-') { tCompoundArgument[1] != '-') {
++it; ++it;
for (size_t j = 1; j < tCompoundArgument.size(); j++) { for (size_t j = 1; j < tCompoundArgument.size(); j++) {
auto tCurrentArgument = std::string{'-', tCompoundArgument[j]}; auto tHypotheticalArgument = std::string{'-', tCompoundArgument[j]};
if (auto tIterator = mArgumentMap.find(tCurrentArgument); auto tIterator2 = mArgumentMap.find(tHypotheticalArgument);
tIterator != mArgumentMap.end()) { if (tIterator2 != mArgumentMap.end()) {
auto tArgument = tIterator->second; auto tArgument = tIterator2->second;
it = tArgument->consume(it, end, tCurrentArgument); it = tArgument->consume(it, end, tHypotheticalArgument);
} else { } else {
throw std::runtime_error("Unknown argument"); throw std::runtime_error("Unknown argument");
} }