2017-09-29 51 views
1

我试图玩弄std :: function和std :: bind,并且我加入了一个问题。我想构建一个通用结构,它允许我将std :: function绑定到成员函数,而不必事先知道成员函数的参数。我写这个东西访问违反std :: function分配给lambda

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...); 
    } 
}; 

FYI我知道,函数的自变量是按值传递(我遇到使用带有可变参数模板普遍引用了一些问题,我将努力稍后)。

这里的问题是,当我用operator()触发函数时,我得到了访问冲突错误。我试图缩小这个问题,并创建了一个没有可变参数的结构(允许成员函数只有一个int作为参数),我看到将lambda赋给std :: function给了我相同的错误,但是如果我用占位符的std :: bind一切都很好。

试验地是这个

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'的构造函数中,您通过值传递成员函数指针(因此将创建一个只存在于构造函数内部的指针副本),然后通过引用将其捕获到lambda中。所以当你调用'caller(10)'时,指针超出了范围。在这个例子中,'instance'很好,因为你通过引用将它传递给了构造函数,当调用'caller(10)'时,'a'仍然在范围内。 (虽然你应该假设未来会发生变化,并围绕它进行设计。) – 0x5453

+1

还值得注意的是,已经存在一个'std :: mem_fn',它应该可以在lambdas或std :: bind中正常工作。 – 0x5453

+0

好了解。我不明白的是我如何解决这个问题。 关于实例:在程序启动时,我将实例化一些类,这些变量将一直可用,直到程序结束。 – Astinog

回答

1

正如评论状态,你有function悬摆指针,你也可以使用:

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

注:instance也应该会超越Caller

0

当对象或其副本超出当前范围时,请勿使用[&]

您正在捕获对局部变量的引用并将它们存储在当前范围之外。