diff --git a/include/continuable/detail/features.hpp b/include/continuable/detail/features.hpp index e59408e..1339130 100644 --- a/include/continuable/detail/features.hpp +++ b/include/continuable/detail/features.hpp @@ -52,15 +52,15 @@ // Detect if the whole standard is available #if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || \ (__cplusplus >= 201703L) - #define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF + #define CONTINUABLE_HAS_CXX17_IF_CONSTEXPR #define CONTINUABLE_HAS_CXX17_DISJUNCTION #define CONTINUABLE_HAS_CXX17_CONJUNCTION #else // Generic feature detection based on __has_feature #if defined(__has_feature) - #if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \ + #if !defined(CONTINUABLE_HAS_CXX17_IF_CONSTEXPR) && \ __has_feature(cxx_if_constexpr) - #define CONTINUABLE_HAS_CXX17_CONSTEXPR_IF + #define CONTINUABLE_HAS_CXX17_IF_CONSTEXPR #endif #endif diff --git a/include/continuable/detail/traits.hpp b/include/continuable/detail/traits.hpp index cba0245..3fffc61 100644 --- a/include/continuable/detail/traits.hpp +++ b/include/continuable/detail/traits.hpp @@ -102,32 +102,78 @@ struct deduce_to_void : std::common_type {}; template using void_t = typename detail::deduce_to_void::type; +#if defined(CONTINUABLE_HAS_CXX17_IF_CONSTEXPR) +#define CONTINUABLE_IF_CONSTEXPR_SELECT_2(EXPR, TRUE_BRANCH) \ + [&](auto) mutable { \ + if constexpr (EXPR) { \ + TRUE_BRANCH \ + } \ + }(0) +#define CONTINUABLE_IF_CONSTEXPR_SELECT_3(EXPR, TRUE_BRANCH, FALSE_BRANCH) \ + [&](auto) mutable { \ + if constexpr (EXPR) { \ + TRUE_BRANCH \ + } else { \ + FALSE_BRANCH \ + } \ + }(0) +#else namespace detail { -template -constexpr void static_if_impl(std::true_type, Type&& type, - TrueCallback&& trueCallback) { - std::forward(trueCallback)(std::forward(type)); +template +constexpr void static_if_impl(std::true_type, TrueCallback&& trueCallback) { + std::forward(trueCallback)(0); } -template -constexpr void static_if_impl(std::false_type, Type&& /*type*/, +template +constexpr void static_if_impl(std::false_type, TrueCallback&& /*trueCallback*/) { } -template -constexpr auto static_if_impl(std::true_type, Type&& type, - TrueCallback&& trueCallback, +template +constexpr auto static_if_impl(std::true_type, TrueCallback&& trueCallback, FalseCallback&& /*falseCallback*/) { - return std::forward(trueCallback)(std::forward(type)); + return std::forward(trueCallback)(0); } -template -constexpr auto static_if_impl(std::false_type, Type&& type, - TrueCallback&& /*trueCallback*/, +template +constexpr auto static_if_impl(std::false_type, TrueCallback&& /*trueCallback*/, FalseCallback&& falseCallback) { - return std::forward(falseCallback)(std::forward(type)); + return std::forward(falseCallback)(0); } +} // namespace detail +#define CONTINUABLE_IF_CONSTEXPR_SELECT_2(EXPR, TRUE_BRANCH) \ + cti::detail::traits::detail::static_if_impl( \ + std::integral_constant{}, [&](auto) mutable { TRUE_BRANCH }) + +#define CONTINUABLE_IF_CONSTEXPR_SELECT_3(EXPR, TRUE_BRANCH, FALSE_BRANCH) \ + cti::detail::traits::detail::static_if_impl( \ + std::integral_constant{}, [&](auto) mutable { TRUE_BRANCH }, \ + [&](auto) { FALSE_BRANCH }) +#endif // CONTINUABLE_HAS_CXX17_IF_CONSTEXPR + +// https://stackoverflow.com/questions/16374776/macro-overloading +// compute number of (variadic) macro arguments from +// http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1 +#define CONTINUABLE_EXPAND(X) X // for MSVC10 compatibility +#define CONTINUABLE_PP_NARG(...) \ + CONTINUABLE_EXPAND(CONTINUABLE_PP_NARG_(__VA_ARGS__, CONTINUABLE_PP_RSEQ_N())) +#define CONTINUABLE_PP_NARG_(...) \ + CONTINUABLE_EXPAND(CONTINUABLE_PP_ARG_N(__VA_ARGS__)) +#define CONTINUABLE_PP_ARG_N(_1, _2, _3, N, ...) N +#define CONTINUABLE_PP_RSEQ_N() 3, 2, 1, 0 + +#define CONTINUABLE_IF_CONSTEXPR_SELECT_(N) CONTINUABLE_IF_CONSTEXPR_SELECT_##N +#define CONTINUABLE_IF_CONSTEXPR_SELECT_EVAL(N) \ + CONTINUABLE_IF_CONSTEXPR_SELECT_(N) + +/// Polyfill for C++17 if constexpr, uses if constexpr when available, +/// otherwise a polyfill through lambdas is used. +#define CONTINUABLE_IF_CONSTEXPR(...) \ + CONTINUABLE_EXPAND(CONTINUABLE_IF_CONSTEXPR_SELECT_EVAL( \ + CONTINUABLE_EXPAND(CONTINUABLE_PP_NARG(__VA_ARGS__)))(__VA_ARGS__)) + +namespace detail { /// Evaluates to the size of the given tuple like type, // / if the type has no static size it will be one. template @@ -159,27 +205,6 @@ constexpr auto sequence_of(identity) noexcept { return std::make_index_sequence(); } -/// Invokes the callback only if the given type matches the check -template -constexpr void static_if(Type&& type, Check&& check, - TrueCallback&& trueCallback) { - detail::static_if_impl(std::forward(check)(type), - std::forward(type), - std::forward(trueCallback)); -} - -/// Invokes the callback only if the given type matches the check -template -constexpr auto static_if(Type&& type, Check&& check, - TrueCallback&& trueCallback, - FalseCallback&& falseCallback) { - return detail::static_if_impl(std::forward(check)(type), - std::forward(type), - std::forward(trueCallback), - std::forward(falseCallback)); -} - /// Calls the given unpacker with the content of the given sequence template constexpr decltype(auto) unpack(std::integer_sequence, diff --git a/include/continuable/detail/util.hpp b/include/continuable/detail/util.hpp index d46b55a..cfb2e0d 100644 --- a/include/continuable/detail/util.hpp +++ b/include/continuable/detail/util.hpp @@ -266,10 +266,4 @@ private: } // namespace detail } // namespace cti -#ifdef CONTINUABLE_CONSTEXPR_IF -#define CONTINUABLE_CONSTEXPR_IF(EXPR, TRUE_BRANCH, FALSE_BRANCH) -#else -#define CONTINUABLE_CONSTEXPR_IF(EXPR, TRUE_BRANCH, FALSE_BRANCH) -#endif // CONTINUABLE_CONSTEXPR_IF - #endif // CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED