2017-09-29 1 views
1

std :: function 및 std :: bind를 가지고 놀려고했는데 문제가있었습니다. 멤버 함수의 선험적 인 인수를 모른 채 멤버 함수에 std :: function을 바인딩 할 수있는 일반 구조를 만들고 싶습니다. 내가std :: function에서 액세스 위반이 람다에게 할당되었습니다.

template<typename Class, typename Return, typename ...Args> 
struct Caller 
{ 
private: 
    std::function<Return(Args ...)> callerFunction; 

    Caller(const Caller&) = delete; 
    Caller(Caller&&) = delete; 
    Caller& operator=(const Caller&) = delete; 

public: 
    ~Caller() = default; 
    Caller() = default; 

    Caller(Class& instance, Return(Class::*function)(Args...)) 
    { 
     callerFunction = [&](Args... args) { return (instance.*function)(args...); }; 
    } 

    Return operator() (Args ... args) 
    { 
     return callerFunction(args...); 
    } 
}; 

가 참고로 나는 함수의 인수가 값에 의해 전달되는 것을 알고이 일을 썼다 (I는 가변 인자 템플릿 보편적 참조를 사용하여 몇 가지 문제가 발생, 그 이후에 작동합니다).

여기서 문제는 operator()로 함수를 실행하면 액세스 위반 오류가 발생한다는 것입니다. 내가 문제를 좁히려 고 variadic 인수 (멤버 함수가 int를 인수로 가질 수 있도록 허용)없이 구조체를 만들려고했는데 std :: function에 람다를 할당하는 것이 나에게 같은 오류를 주었다. 그러나 if std :: bind를 placeholder와 함께 사용하면 모든 것이 잘되었습니다.

테스트 지상 내가 제대로 멤버 함수를 호출하기 위해 클래스의 인스턴스를 저장해야 할, 람다를 사용하여이

class A 
{ 
public: 
    bool foo(int a) 
    { 
     std::cout << a << std::endl; 
     return true; 
    } 
}; 

int main() 
{ 
    A a; 
    a.foo(9); 

    Caller<A, bool, int> caller(a, &A::foo); 
    caller(10); 

    std::cin.ignore(); 
} 

입니까?

+1

나는 UB를 가졌을 것이라고 확신한다. 'Caller'의 생성자에서는 멤버 함수 포인터를 값으로 전달합니다 (그래서 생성자 내부에만 존재하는 포인터 복사본이 생성됩니다). 그런 다음 참조로 람다에서 그 함수를 캡처합니다. 그래서'caller (10) '이라고 부를 때쯤에 포인터가 범위를 벗어납니다. 'instance'는 생성자에게 참조로 전달하기 때문에이 예제에서는 괜찮습니다. 그리고'caller (10)'을 호출 할 때'a'는 여전히 범위 내에 있습니다. (당신이 미래에 그것을 바꿀 것이라고 가정해야한다.) – 0x5453

+1

lambda 나'std :: bind'에서 잘 동작 할'std :: mem_fn' 파일이 이미 존재한다는 점도 주목할 가치가있다. – 0x5453

+0

알았습니다. 내가 이해할 수없는 것은이 문제를 어떻게 해결할 수 있는가하는 것이다. 인스턴스 정보 : 프로그램을 시작할 때 일부 클래스가 인스턴스화되고 해당 변수는 프로그램이 끝날 때까지 사용할 수 있습니다. – Astinog

답변

1

코멘트의 상태로서, 당신은 function의 허상 포인터를 대신 사용할 수 있습니다

Caller(Class& instance, Return(Class::*function)(Args...)) 
{ 
    callerFunction = [&instance, function](Args... args) { 
     return (instance.*function)(std::forward<Args>(args)...); 
    }; 
} 

참고 : instanceCaller을 들보 다 오래 남았습니다한다.

0

개체 또는 복사본이 현재 범위보다 오래 지속되는 경우 [&]을 사용하지 마십시오.

로컬 변수에 대한 참조를 캡처하고 현재 범위를 벗어나 저장합니다.