Skip to content

Instantly share code, notes, and snippets.

@ericniebler
Created October 12, 2020 21:21
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ericniebler/056f5459cf259da526d9ea2279c386bb to your computer and use it in GitHub Desktop.
Save ericniebler/056f5459cf259da526d9ea2279c386bb to your computer and use it in GitHub Desktop.
Simple implementation of the tag_invoke customization point
#include <utility>
#include <type_traits>
namespace _tag_invoke {
void tag_invoke();
struct _fn {
template <typename CPO, typename... Args>
constexpr auto operator()(CPO cpo, Args&&... args) const
noexcept(noexcept(tag_invoke((CPO &&) cpo, (Args &&) args...)))
-> decltype(tag_invoke((CPO &&) cpo, (Args &&) args...)) {
return tag_invoke((CPO &&) cpo, (Args &&) args...);
}
};
template <typename CPO, typename... Args>
using tag_invoke_result_t = decltype(
tag_invoke(std::declval<CPO>(), std::declval<Args>()...));
using yes_type = char;
using no_type = char(&)[2];
template <typename CPO, typename... Args>
auto try_tag_invoke(int) //
noexcept(noexcept(tag_invoke(
std::declval<CPO>(), std::declval<Args>()...)))
-> decltype(static_cast<void>(tag_invoke(
std::declval<CPO>(), std::declval<Args>()...)), yes_type{});
template <typename CPO, typename... Args>
no_type try_tag_invoke(...) noexcept(false);
template <template <typename...> class T, typename... Args>
struct defer {
using type = T<Args...>;
};
struct empty {};
} // namespace _tag_invoke
namespace _tag_invoke_cpo {
inline constexpr _tag_invoke::_fn tag_invoke{};
}
using namespace _tag_invoke_cpo;
template <auto& CPO>
using tag_t = std::remove_cvref_t<decltype(CPO)>;
using _tag_invoke::tag_invoke_result_t;
template <typename CPO, typename... Args>
inline constexpr bool is_tag_invocable_v =
(sizeof(_tag_invoke::try_tag_invoke<CPO, Args...>(0)) ==
sizeof(_tag_invoke::yes_type));
template <typename CPO, typename... Args>
struct tag_invoke_result
: std::conditional_t<
is_tag_invocable_v<CPO, Args...>,
_tag_invoke::defer<tag_invoke_result_t, CPO, Args...>,
_tag_invoke::empty>
{};
template <typename CPO, typename... Args>
using is_tag_invocable = std::bool_constant<is_tag_invocable_v<CPO, Args...>>;
template <typename CPO, typename... Args>
inline constexpr bool is_nothrow_tag_invocable_v =
noexcept(_tag_invoke::try_tag_invoke<CPO, Args...>(0));
template <typename CPO, typename... Args>
using is_nothrow_tag_invocable =
std::bool_constant<is_nothrow_tag_invocable_v<CPO, Args...>>;
template <typename CPO, typename... Args>
concept tag_invocable =
(sizeof(_tag_invoke::try_tag_invoke<CPO, Args...>(0)) ==
sizeof(_tag_invoke::yes_type));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment