1

나중에 실행할 수 있도록 매개 변수와 함께 일부 작업을 저장하는 코드를 작성했습니다. 코드 :"변수"로 매개 변수를 variadic 기반 템플릿에 전달할 수 없습니다.

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)(Types...); 

    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<typename 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<typename 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; 
} 

그러나 문제는 내가에만이 방법으로 이러한 작업을 생성 할 수 있습니다 :

TaskInterface* st = CreateSimpleTask(test1, 5); 

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

을 할 수없는 이러한 방법 :

// error C2664: 'double (int)' : cannot convert argument 1 from 'int *' to 'int' 
int xxxx; 
TaskBase* st = CreateSimpleTask(test1, &xxxx); 

또는 MemberTask에 대한 :

// cannot convert argument 2 from 'bool (__thiscall Test::*)(std::string)' to 'bool (__thiscall Test::*)(std::string &)' 
std::string ss = "sdfsdf"; 
TaskBase* mt = CreateMemberTask(&t, &Test::doIt, ss); 

어떻게 수정할 수 있습니까? y 클래스는 "value"뿐만 아니라 "variables"도 매개 변수를 전달할 수 있습니까? 또는이 모든 목적을 위해 내 "아키텍처"가 완전히 잘못 되었습니까?

+1

저장하고 싶으면'std :: bind' 나 lambda를'std :: function'과 함께 사용해야합니다. 코드를 저장하는 것이 훨씬 간단합니다. – Holt

+0

실제 줄과 전체 오류가 유용합니다. 오류를 이해하지 못한다면 오류를 편집하는 것은 좋지 않습니다. – Yakk

+0

[C++ 17의 std :: apply'] (http : // ko)에 해당하는 [이 대답] (http://stackoverflow.com/a/20441189/1023390)을 보길 원할 수 있습니다. cppreference.com/w/cpp/utility/apply). – Walter

답변

1

특정 서명과 해당 인수가있는 함수를 저장하는 것보다 훨씬 간단한 방법은 인수가없는 함수와 해당 컨텍스트 (썽크라고도 함)를 저장하는 것입니다.

std::function<void()> st = [] { test1(5); }; 
std::function<void()> mt = [&] { t.doIt(ss); }; 

이것은 훨씬 간단하며 코드와 달리 메모리가 누출되지 않습니다. 값, 참조 또는 조합을 사용하여 컨텍스트를 캡처 할 수 있습니다. 람다는 멋지다! http://en.cppreference.com/w/cpp/language/lambda.