Last active
December 20, 2024 13:06
-
-
Save schaumb/9979271308242b5004d871d343f0393a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
namespace Impl { | |
// <e> <e> <e> <e> | |
// const | |
// volatile | |
// & | |
// && | |
// noexcept [only >= c++17] | |
// 2 * 2 * 3 * 2 = 24 template spec | |
template<class...> | |
struct args_impl; | |
template<class T> | |
struct mem_ptr_impl; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...)> { | |
using this_t = Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const> { | |
using this_t = const Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile> { | |
using this_t = volatile Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile> { | |
using this_t = const volatile Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) &> { | |
using this_t = Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const &> { | |
using this_t = const Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile &> { | |
using this_t = volatile Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile &> { | |
using this_t = const volatile Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) &&> { | |
using this_t = Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const &&> { | |
using this_t = const Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile &&> { | |
using this_t = volatile Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile &&> { | |
using this_t = const volatile Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...); | |
}; | |
template<typename T, typename U = void> | |
constexpr bool is_noexcept_v = false; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) noexcept> { | |
using this_t = Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const noexcept> { | |
using this_t = const Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile noexcept> { | |
using this_t = volatile Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile noexcept> { | |
using this_t = const volatile Class; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) & noexcept> { | |
using this_t = Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const & noexcept> { | |
using this_t = const Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile & noexcept> { | |
using this_t = volatile Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile & noexcept> { | |
using this_t = const volatile Class &; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) && noexcept> { | |
using this_t = Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const && noexcept> { | |
using this_t = const Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) volatile && noexcept> { | |
using this_t = volatile Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<class Res, class Class, class ...Args> | |
struct mem_ptr_impl<Res (Class::*)(Args...) const volatile && noexcept> { | |
using this_t = const volatile Class &&; | |
using args_t = args_impl<Args...>; | |
using res_t = Res; | |
using fun_ptr_t = res_t (*)(std::remove_reference_t<this_t>*, Args...) noexcept; | |
using is_noexcept = std::true_type; | |
}; | |
template<typename T> | |
constexpr bool is_noexcept_v<T, std::void_t<typename T::is_noexcept>> = typename T::is_noexcept{}(); | |
template<class fun_ptr_t, class this_t, class res_t, class args_t, bool cexpr, auto N> | |
constexpr fun_ptr_t ptr_from_mptr_impl = [] { | |
static_assert(!std::is_same_v<this_t, this_t>, "Not a member pointer"); | |
return nullptr; | |
} (); | |
template<class fun_ptr_t, class this_t, class res_t, class ... Args, bool cexpr, auto N> | |
constexpr fun_ptr_t ptr_from_mptr_impl<fun_ptr_t, this_t, res_t, args_impl<Args...>, cexpr, N> = | |
+[](std::remove_reference_t<this_t>* this_, Args... args) noexcept(cexpr) -> res_t { | |
return (std::forward<this_t>(*this_).*N)(std::forward<Args>(args)...); | |
}; | |
} | |
template<auto N, typename mptr_impl = Impl::mem_ptr_impl<std::remove_reference_t<decltype(N)>>> | |
constexpr auto ptr_from_mptr = Impl::ptr_from_mptr_impl<typename mptr_impl::fun_ptr_t, | |
typename mptr_impl::this_t, | |
typename mptr_impl::res_t, | |
typename mptr_impl::args_t, | |
Impl::is_noexcept_v<mptr_impl>, N>; | |
#include <iostream> | |
struct A { | |
void fun1() { | |
std::cout << "fun1 called\n"; | |
} | |
int fun2(float f) const { | |
return f*2; | |
} | |
}; | |
int main() { | |
A a; | |
constexpr auto const_fun1 = ptr_from_mptr<&A::fun1>; | |
constexpr auto const_fun2 = ptr_from_mptr<&A::fun2>; | |
const_fun1(&a); | |
std::cout << const_fun2(&a, 21) << "\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment