Skip to content

Instantly share code, notes, and snippets.

@elbeno
Last active March 5, 2016 18:56
Show Gist options
  • Save elbeno/82534e0893f559a0126a to your computer and use it in GitHub Desktop.
Save elbeno/82534e0893f559a0126a to your computer and use it in GitHub Desktop.
Forwarding to a member function using a tuple
#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