Skip to content

Instantly share code, notes, and snippets.

@vmrob
Last active March 3, 2016 10:32
Show Gist options
  • Select an option

  • Save vmrob/c177309d66a3989f4d85 to your computer and use it in GitHub Desktop.

Select an option

Save vmrob/c177309d66a3989f4d85 to your computer and use it in GitHub Desktop.

Revisions

  1. vmrob revised this gist Mar 3, 2016. 1 changed file with 28 additions and 2 deletions.
    30 changes: 28 additions & 2 deletions forward_tuple.cpp
    Original file line number Diff line number Diff line change
    @@ -173,6 +173,28 @@ constexpr auto forward_tuple(F&& f, std::tuple<Args...>&& args) {
    );
    }

    template <typename F, typename... Args>
    class bound_function {
    public:
    bound_function(F f, Args... args)
    : _f(std::move(f))
    , _args(std::forward<Args>(args)...)
    {}

    auto operator()(){
    return forward_tuple(std::move(_f), std::move(_args));
    }

    private:
    F _f;
    std::tuple<Args...> _args;
    };

    template <typename... Args>
    auto bind(Args&&... args) {
    return bound_function<Args...>(std::forward<Args>(args)...);
    }

    template <typename T>
    struct Vector2 {
    void setX(T v) { x = v; }
    @@ -186,13 +208,17 @@ struct Vector2 {

    using Vector2f = Vector2<float>;

    #include <iostream>
    #include <cstdio>

    int main() {

    Vector2f vec{0.0f, 2.0f};

    forward_tuple(&Vector2f::setX, std::make_tuple(&vec, 3.0f));
    auto f = bind(&Vector2f::setX, &vec, 3.0f);

    printf("%f\n", vec.getX());

    f();

    printf("%f\n", vec.getX());
    }
  2. vmrob created this gist Mar 3, 2016.
    198 changes: 198 additions & 0 deletions forward_tuple.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,198 @@
    #include <utility>
    #include <tuple>
    #include <type_traits>

    namespace meta {

    // detects callable objects, not functions
    // http://stackoverflow.com/questions/15393938/find-out-if-a-c-object-is-callable
    template<typename T>
    class is_callable_object {
    private:
    using yes = char(&)[1];
    using no = char(&)[2];

    struct Fallback { void operator()(); };
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    template<typename>
    static yes test(...);

    template<typename C>
    static no test(Check<void (Fallback::*)(), &C::operator()>*);

    public:
    static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
    };

    template <typename T>
    static constexpr auto is_callable_object_v = is_callable_object<T>::value;

    // function traits

    inline namespace detail {

    template <typename ReturnType, typename ClassType, typename ... Args>
    struct mem_function_traits {
    static constexpr auto arity = sizeof...(Args);

    using result_type = ReturnType;
    using class_type = ClassType;
    static constexpr auto valid = true;

    template <size_t i>
    struct arg {
    using type = std::tuple_element_t<i, std::tuple<Args...>>;
    };

    template <size_t i>
    using arg_t = typename arg<i>::type;
    };

    template <typename ReturnType, typename ... Args>
    struct reg_function_traits {
    static constexpr auto arity = sizeof...(Args);

    using result_type = ReturnType;
    static constexpr auto valid = true;

    template <size_t i>
    struct arg {
    using type = decltype(std::get<i>(std::tuple<Args...>()));
    };

    template <size_t i>
    using arg_t = typename arg<i>::type;
    };

    } // namespace detail

    // no types defined
    template <typename T, typename = void, typename = void>
    struct function_traits {
    static constexpr auto valid = false;
    };

    // generic functions
    template <typename T>
    struct function_traits<T,
    std::enable_if_t<std::is_class<T>::value>,
    std::enable_if_t<is_callable_object_v<T>>>
    : public function_traits<decltype(&T::operator())>
    { };

    template <typename T>
    struct function_traits<T,
    std::enable_if_t<std::is_reference<T>::value>>
    : public function_traits<typename std::remove_reference_t<T>>
    { };

    // const member functions
    template <typename ReturnType, typename ClassType, typename... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...) const,
    std::enable_if_t<std::is_member_function_pointer<ReturnType(ClassType::*)(Args...)>::value>>
    : public mem_function_traits<ReturnType, ClassType, Args...>
    { };

    // member functions
    template <typename ReturnType, typename ClassType, typename ... Args>
    struct function_traits<ReturnType(ClassType::*)(Args...),
    std::enable_if_t<std::is_member_function_pointer<ReturnType(ClassType::*)(Args...)>::value>>
    : public mem_function_traits<ReturnType, ClassType, Args...>
    { };

    // regular functions
    template <typename ReturnType, typename ... Args>
    struct function_traits<ReturnType(Args...),
    std::enable_if_t<std::is_function<ReturnType(Args...)>::value>>
    : public reg_function_traits<ReturnType, Args...>
    { };

    // is_callable

    template <typename T>
    struct is_callable : public std::integral_constant<bool, function_traits<T>::valid> {};

    // result_of

    template <typename T>
    struct result_of {
    using type = std::result_of_t<T>;
    };

    template <typename R, typename... Args>
    struct result_of<R(*)(Args...)> {
    using type = R;
    };

    template <typename R, typename... Args>
    struct result_of<R(&)(Args...)> {
    using type = R;
    };

    template <typename R, typename C, typename ... Args>
    struct result_of<R(C::*)(Args...)> {
    using type = R;
    };

    template <typename R, typename C, typename ... Args>
    struct result_of<R(C::*)(Args...) const> {
    using type = R;
    };

    } // namespace meta

    template <typename F, typename = void>
    struct forward_tuple_impl {
    template <typename... TupleArgs, size_t... I, typename = void>
    auto operator()(F&& f, std::tuple<TupleArgs...>&& tuple, std::index_sequence<I...>) {
    return f(std::get<I>(std::forward<std::tuple<TupleArgs...>>(tuple))...);
    }
    };

    template <typename F>
    struct forward_tuple_impl<F, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
    template <typename ClassPtrType, typename... TupleArgs, size_t... I>
    auto operator()(F&& f, std::tuple<ClassPtrType, TupleArgs...>&& tuple, std::index_sequence<0, I...>) {
    static_assert(
    std::is_same<std::remove_cv_t<typename meta::function_traits<F>::class_type*>, std::remove_cv_t<ClassPtrType>>::value,
    "First argument in parameter pack must be a pointer to an class with member function F");

    return (std::get<0>(tuple)->*f)(std::get<I>(std::forward<std::tuple<ClassPtrType, TupleArgs...>>(tuple))...);
    }
    };

    template<typename F, typename... Args>
    constexpr auto forward_tuple(F&& f, std::tuple<Args...>&& args) {
    return forward_tuple_impl<F>()(
    std::forward<F>(f),
    std::forward<std::tuple<Args...>>(args),
    std::index_sequence_for<Args...>{}
    );
    }

    template <typename T>
    struct Vector2 {
    void setX(T v) { x = v; }
    void setY(T v) { y = v; }
    T getX() { return x; }
    T getY() { return y; }

    T x;
    T y;
    };

    using Vector2f = Vector2<float>;

    #include <iostream>

    int main() {

    Vector2f vec{0.0f, 2.0f};

    forward_tuple(&Vector2f::setX, std::make_tuple(&vec, 3.0f));

    printf("%f\n", vec.getX());
    }