LoginSignup
3
3

More than 5 years have passed since last update.

複数の関数オブジェクトを1つにまとめる2

Posted at

複数の関数オブジェクトを1つにまとめるの続きです
関数オブジェクトの戻り値をtupleにして返すようにしました

#include <tuple>
#include <iostream>
#include <cstddef>

template <std::size_t... I>
class index_tuple{
public:
    using type = index_tuple<I...>;
};

template <class Left, class Right>
class concat_impl;
template <std::size_t... Left, std::size_t... Right>
class concat_impl<index_tuple<Left...>, index_tuple<Right...>>
    : public index_tuple<Left..., Right...>
{
};
template <class Left, class Right>
using concat = typename concat_impl<Left, Right>::type;

template <class Sequence, std::size_t N>
class shift_impl;
template <std::size_t N, std::size_t... I>
class shift_impl<index_tuple<I...>, N>
    : public index_tuple<(I + N)...>
{
};
template <class Sequence, std::size_t N>
using shift = typename shift_impl<Sequence, N>::type;

template <std::size_t Begin, std::size_t End>
class make_index_range_impl;
template <std::size_t Begin, std::size_t End>
using make_index_range = typename make_index_range_impl<Begin, End>::type;

template <std::size_t Begin, std::size_t End>
class make_index_range_impl:
    public shift< concat<
        make_index_range<0, (End - Begin) / 2>,
        shift<make_index_range<0, (End - Begin) / 2 + (End - Begin) % 2>, (End - Begin) / 2>
    >, Begin>
{
};

template <>
class make_index_range_impl<0, 1>: public index_tuple<0>
{
};
template <>
class make_index_range_impl<0, 0>: public index_tuple<>
{
};

template <std::size_t N>
using make_index = make_index_range<0, N>;


class nil{
public:
    template <class T>
    void operator=(const T&)
    {
    }
    template <class T>
    operator T()
    {
        return T();
    }
};


template <class ArgsTuple, class FunctionsTuple>
class combiner;
template <class... Args, class... Functions>
class combiner<std::tuple<Args...>, std::tuple<Functions...>>{

    template <class Function>
    class result{
        using result_type = typename std::result_of<Function(Args...)>::type;

    public:
        using type = std::conditional_t<std::is_void<result_type>::value, nil, result_type>;
    };

    using function_tuple = std::tuple<Functions...>;
    using arg_tuple = std::tuple<Args...>;
    using result_tuple = std::tuple<typename result<Functions>::type...>;

    function_tuple functions;
    result_tuple a;

public:
    combiner(Functions... functions): functions(functions...)
    {
    }

    result_tuple operator()(Args... args)
    {
        return operator_helper(make_index<sizeof...(Functions)>(), args...);
    }

private:
    template <std::size_t... Indices>
    result_tuple operator_helper(index_tuple<Indices...>, Args... args)
    {
        return result_tuple(bind<Indices>(args...)...);
    }

    template <std::size_t I>
    typename std::tuple_element<I, result_tuple>::type bind(Args... args)
    {
        using result_type = typename std::tuple_element<I, result_tuple>::type;
        return bind_helper<result_type>(std::get<I>(functions), args...);
    }

    template <class Result, class Function>
    class bind_helper_class{
        Result result;

    public:
        bind_helper_class(Function &f, Args... args): result(f(args...))
        {
        }
        operator Result()
        {
            return result;
        }
    };

    template <class Function>
    class bind_helper_class<nil, Function>{
    public:
        bind_helper_class(Function &f, Args... args)
        {
            f(args...);
        }
        operator nil()
        {
            return nil();
        }
    };

    template <class Result, class Function>
    bind_helper_class<Result, Function> bind_helper(Function &f, Args... args)
    {
        return bind_helper_class<Result, Function>(f, args...);
    }
};

template <class... Args, class... Functions>
combiner<std::tuple<Args...>, std::tuple<Functions...>> make_combiner(Functions... functions)
{
    return combiner<std::tuple<Args...>, std::tuple<Functions...>>(functions...);
}


double function(int x, double y)
{
    return x * y;
}

class Class{
public:
    int operator()(int x, double)
    {
        return x;
    }
};

int main()
{
    auto combiner = make_combiner<int, double>(function, Class(), [](int, double){});
    double a;
    int b;

    std::tie(a, b, std::ignore) = combiner(10, 20.);
    std::cout << a << ' ' << b << std::endl;
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3