Skip to content

Instantly share code, notes, and snippets.

@schaumb
Last active August 15, 2022 11:53
Show Gist options
  • Save schaumb/9979271308242b5004d871d343f0393a to your computer and use it in GitHub Desktop.
Save schaumb/9979271308242b5004d871d343f0393a to your computer and use it in GitHub Desktop.
member pointer to pointer constexpr conversion
#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_constexpr_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_constexpr_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_constexpr_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