Last active
March 5, 2016 18:56
-
-
Save elbeno/82534e0893f559a0126a to your computer and use it in GitHub Desktop.
Forwarding to a member function using a tuple
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 <cstddef> | |
#include <iostream> | |
#include <string> | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
using namespace std; | |
template <typename T> | |
struct function_traits | |
: public function_traits<decltype(&T::operator())> | |
{}; | |
template <typename C, typename R, typename... A> | |
struct function_traits<R(C::*)(A...)> | |
{ | |
using class_type = C; | |
}; | |
template <typename C, typename R, typename... A> | |
struct function_traits<R(C::*)(A...) const> | |
: public function_traits<R(C::*)(A...)> | |
{}; | |
template <typename F, | |
typename = std::enable_if_t<!std::is_member_function_pointer<F>::value>, | |
typename T, size_t... I> | |
constexpr auto forward_tuple_impl(F&& f, T&& t, std::index_sequence<I...>) noexcept | |
{ | |
return f(std::get<I>(std::forward<T>(t))...); | |
} | |
template <typename F, | |
typename = std::enable_if_t<std::is_member_function_pointer<F>::value>, | |
typename T, size_t... I> | |
constexpr auto forward_tuple_impl(F&& f, T&& t, std::index_sequence<0, I...>) noexcept | |
{ | |
// class type from first tuple argument | |
using tuple_class_t = std::remove_cv_t<std::remove_pointer_t< | |
std::tuple_element_t<0, std::remove_reference_t<decltype(t)>>>>; | |
// class type from the member function pointer | |
using arg_class_t = std::remove_cv_t<typename function_traits<F>::class_type>; | |
static_assert(std::is_base_of<arg_class_t, tuple_class_t>::value, | |
"First argument in parameter pack must be a pointer " | |
"to the class containing the member function F"); | |
return (std::get<0>(std::forward<T>(t))->*f)( | |
std::get<I>(std::forward<T>(t))...); | |
} | |
template <typename F, typename T> | |
constexpr auto forward_tuple(F&& f, T&& args) noexcept | |
{ | |
return forward_tuple_impl( | |
std::forward<F>(f), | |
std::forward<T>(args), | |
std::make_index_sequence<std::tuple_size<std::decay_t<T>>{}>{}); | |
} | |
struct Base | |
{ | |
int F1(int x, int y) const { return x + y; } | |
string F2(const string& x, const string& y) { return x + y; } | |
int F3(int x, int y) const { return x * y; } | |
}; | |
struct Derived : public Base | |
{ | |
}; | |
int Func(int x, int y) { return y - x; } | |
int main(void) | |
{ | |
Base b; | |
cout << forward_tuple(&Base::F1, make_tuple(&b, 3, 5)) << endl; | |
cout << forward_tuple(&Base::F2, make_tuple(&b, "Hello, ", "World!")) << endl; | |
cout << forward_tuple(&Base::F3, make_tuple(&b, 3, 5)) << endl; | |
Derived d; | |
cout << forward_tuple(&Base::F3, make_tuple(&d, 3, 5)) << endl; | |
cout << forward_tuple(&Derived::F3, make_tuple(&d, 3, 5)) << endl; | |
cout << forward_tuple(&Func, make_tuple(3, 5)) << endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment