user2123079
user2123079

Reputation: 686

Store variadic arguments in class template

I'm trying to make some manager that will work with tasks after some timeout or at some time etc. For this manager I'm developing task classes that I can save in this manager and execute later on. So far I've got these classes, but there is an error during compilation. Because I'm newbie in templates, I can't figure out where is the problem. Everything is just fine, except creating task from class object. But if the method in those object will not have parameters, everything will be fine. I used also code from here. So, my code is:

class TaskInterface
{
public:
    virtual void Execute() = 0;
};

//************************************************************

namespace TaskHelper
{
    template <std::size_t... Types>
    struct index {};

    template <std::size_t N, std::size_t... Types>
    struct gen_seq : gen_seq<N - 1, N - 1, Types...> {};

    template <std::size_t... Types>
    struct gen_seq<0, Types...> : index<Types...>{};
}

//************************************************************

template <typename ReturnType, typename... Types>
class SimpleTask : public TaskInterface
{
public:
    template <typename Function>
    SimpleTask(Function&& func, Types&&... args)
        : m_function(std::forward<Function>(func)),
        m_args(std::make_tuple(std::forward<Types>(args)...)) {
    }

    void Execute() override final
    {
        func(m_args);
    }

private:
    std::function<ReturnType(Types...)> m_function;
    std::tuple<Types...> m_args;

    template <typename... Args, std::size_t... Is>
    void func(std::tuple<Args...>& tup, TaskHelper::index<Is...>)
    {
        m_function(std::get<Is>(tup)...);
    }

    template <typename... Args>
    void func(std::tuple<Args...>& tup)
    {
        func(tup, TaskHelper::gen_seq<sizeof...(Args)>{});
    }
};

//************************************************************

template < typename ReturnType, class Class, typename... Types>
class MemberTask : public TaskInterface
{
public:
    typedef ReturnType(Class::*Method)();

    MemberTask(Class* object, Method method, Types&&... args) :
        m_object(object), m_method(method), m_args(std::make_tuple(std::forward<Types>(args)...)) {
    };

    void Execute() override final
    {
        func(m_args);
    };

private:
    Class* m_object;
    Method m_method;
    std::tuple<Types...> m_args;

    template <typename... Args, std::size_t... Is>
    void func(std::tuple<Args...>& tup, TaskHelper::index<Is...>)
    {
        (m_object->*m_method)(std::get<Is>(tup)...);
    }

    template <typename... Args>
    void func(std::tuple<Args...>& tup)
    {
        func(tup, TaskHelper::gen_seq<sizeof...(Args)>{});
    }
};

//************************************************************

template <typename Function, typename... Arguments>
TaskInterface* CreateSimpleTask(Function&& func, Arguments&&... args)
{
    return new SimpleTask<std::result_of<decltype(func)(Arguments...)>::type, Arguments...>(std::forward<Function>(func), std::forward<Arguments>(args)...);
}

template <class Class, typename Method, typename... Arguments>
TaskInterface* CreateMemberTask(Class* obj, Method method, Arguments&&... args)
{
    return new MemberTask<std::result_of<decltype(method)(Class)>::type, Class, Arguments...>(std::forward<Class*>(obj), std::forward<Method>(method), std::forward<Arguments>(args)...);
}

//************************************************************

class Test {
public:
    Test() { id = ++m_id; }
    bool doIt(int n) {
        std::cout << "doIt of " << n * id;
        return true;
    };

private:
    static int m_id;
    int id;
};

int Test::m_id = 0;


double test1(int xs)
{
    xs *= 555;
    return 66.02l;
}

int main()
{
    TaskInterface* st = CreateSimpleTask(test1, 5);
    st->Execute();

    Test t;

    TaskInterface* mt = CreateMemberTask(&t, &Test::doIt, 66);
    mt->Execute();

    return 0;
}

UPD1: During compilation I've got following error:

error C2664: 'MemberTask<bool,Class,int>::MemberTask(const MemberTask<bool,Class,int> &)' : cannot convert argument 2 from 'bool (__thiscall Test::* )(int)' to 'bool (__thiscall Test::* )(void)'

Upvotes: 0

Views: 712

Answers (1)

max66
max66

Reputation: 66230

I suggest you some corrections

(1) in MemberTask, the definition of the Method type should include the arguments of the method; so, instead of

typedef ReturnType(Class::*Method)();

you should write

typedef ReturnType(Class::*Method)(Types...);

(2) in CreateSimpleTask(), instead of

return new SimpleTask<
   std::result_of<decltype(func)(Arguments...)>::type,
   Arguments...>(std::forward<Function>(func), std::forward<Arguments>(args)...);

you should add a typename before std::result_of, so

return new SimpleTask<
   typename std::result_of<decltype(func)(Arguments...)>::type, 
   Arguments...>(std::forward<Function>(func), std::forward<Arguments>(args)...);

(3) in CreateMemberTask() you have forgotten the typename and the arguments of the method; so, instead of

return new MemberTask<
   std::result_of<decltype(method)(Class)>::type,
   Class, Arguments...>(std::forward<Class*>(obj), std::forward<Method>(method), 
                        std::forward<Arguments>(args)...);

you should write

return new MemberTask<
   typename std::result_of<decltype(method)(Class, Arguments...)>::type,
   Class, Arguments...>(std::forward<Class*>(obj), std::forward<Method>(method),
                        std::forward<Arguments>(args)...);

Upvotes: 3

Related Questions