2017-09-29 111 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

當對象或其副本超出當前範圍時,請勿使用[&]

您正在捕獲對局部變量的引用並將它們存儲在當前範圍之外。