LoginSignup
1
1

More than 5 years have passed since last update.

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

Posted at

同じ引数で複数の関数オブジェクトを同時に呼び出す必要があったので勉強を兼ねて作ってみました

#include <iostream>
#include <tuple>
#include <string>


template <std::size_t... Indices>
class sequence{
public:
    using type = sequence<Indices...>;
};

template <class, class>
class concat_impl;
template <std::size_t... Left, std::size_t... Right>
class concat_impl<sequence<Left...>, sequence<Right...>>: public sequence<Left..., Right...>
{
};

template <class Left, class Right>
using concat = typename concat_impl<Left, Right>::type;

template <class, std::size_t>
class shift_impl;
template <std::size_t N, std::size_t... Indices>
class shift_impl<sequence<Indices...>, N>: public sequence<(Indices + 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_sequence_impl:
    public shift< concat<
        typename make_sequence_impl<0, (End - Begin) / 2>::type,
        shift<typename make_sequence_impl<0, (End - Begin) / 2 + (End - Begin) % 2>::type, (End - Begin) / 2>
    >, Begin>
{
};

template <>
class make_sequence_impl<0, 1>: public sequence<0>
{
};

template <>
class make_sequence_impl<0, 0>: public sequence<>
{
};

template <std::size_t Begin, std::size_t End>
using make_sequence = typename make_sequence_impl<Begin, End>::type;


template <class... Functions>
class caller{ 
    std::tuple<Functions...> functions;

    template <std::size_t Head, std::size_t... Tail, class... Args>
    void call_impl(sequence<Head, Tail...>, Args... args)
    {
        std::get<Head>(functions)(args...);
        call_impl(sequence<Tail...>(), args...);
    }

    template <class... Args>
    void call_impl(sequence<>, Args...)
    {
    }

public:
    caller(Functions... funcs): functions(funcs...)
    {
    }

    template <class... Args>
    void operator()(Args... args)
    {
        call_impl(make_sequence<0, sizeof...(Functions)>(), args...);
    }
};

template <class... Functions>
caller<Functions...> make_caller(Functions... funcs)
{
    return caller<Functions...>(funcs...);
}


void function(const char *s, int a, int b)
{
    std::cout << "void function(const char *, int, int): " << s << ' ' << a << ' ' << b << std::endl;
}

class Class1{
public:
    void operator()(std::string s, int a, int b)
    {
        std::cout << "Class1::operator()(): " << s << ' ' << a << ' ' << b << std::endl;
    }
};

class Class2{
public:
    template <class Type>
    void operator()(Type s, int a, int b)
    {
        std::cout << "Class2::operator()(): " << s << ' ' << a << ' ' << b << std::endl;
    }
};

int main()
{
    make_caller()();

    auto caller = make_caller([](const char *s, int a, ...){
        std::cout << "first lambda function: " << s << ' ' << a << std::endl;
    }, [](const char *s, int a, int b){
        std::cout << "second second function: " << s << ' ' << a << ' ' << b << std::endl;
    }, function, Class1(), Class2());

    caller("string1", 0, 1);
    std::cout << std::endl;
    caller("string2", 2, 3);

    return 0;
}

1
1
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
1
1