2014-12-29 59 views
1

我有這樣的代碼,嘗試的模板參數完美轉發通過中間類裝入std::functionRvalue引用參數在通過std :: forward傳遞時到期?

#include <functional> 
#include <vector> 
#include <algorithm> 
#include <iterator> 
#include <memory> 
#include <iostream> 

template <typename ...Arguments> 
class CSignal 
{ 
public: 
    typedef std::function<void (Arguments...)> SignalFunction; 
public: 
    void connect(const SignalFunction& target) 
    { 
     m_connections.emplace_back(std::make_shared<SignalFunction>(target)); 
    } 

    template <typename ...ActualArguments> 
    void invoke(ActualArguments&&... args) const 
    { 
     for (auto& connection: m_connections) 
      if (connection) 
       (*connection)(std::forward<ActualArguments>(args)...); 
    } 

private: 
    std::vector<std::shared_ptr<SignalFunction>> m_connections; 
}; 


struct A 
{ 
    void f() {std::cout << __FUNCTION__ << "\n";} 
}; 

void test(std::shared_ptr<A> ptr) 
{ 
    if (ptr) 
     ptr->f(); 
} 

int main() 
{ 
    CSignal<std::shared_ptr<A>> signal; 
    signal.connect(test); 
    signal.connect(test); 

    signal.invoke(std::make_shared<A>()); 

    return 0; 
} 

問題:test叫了兩次,它就是所謂它的參數,第二次是empty指針。爲什麼?

如果我刪除std::forward問題消失,但那不是我想要的。

回答

2

是;當ActualArguments不是引用類型時,std::forwardstd::move做同樣的事情。

根據到期情況,forward需要與move一樣對待。通常,在循環內部不需要forwardmove

如果您想在最後一次循環迭代中移動參數,您必須將其從循環中分離出來。這可能意味着不使用range-for語法。但是,您可能會問這是否值得優化,並考慮在稍後有更多性能數據可用時將其保存。

+0

對不起,我不明白,你能擴大答案嗎?我的理解是,所有'std :: move'都會返回它的參數作爲右值引用,從而失去參數的名稱以使其成爲右值。但是原始的'args'參數在外部範圍中繼續存在(並且它是一個左值,即使它是rvalue,其中'invoke'被調用),它爲什麼會被破壞?這裏本身沒有任何動作,只是參數傳遞! –

+0

@VioletGiraffe'std :: move'(有時候是'std :: forward')導致它的參數被解釋爲一個右值,這可能導致過期發生在一個函數中,該函數明確將其作爲右值接收。前進/移動助手功能產生一個特權,可以通過例如'test'。在這種情況下,'test'總是使右值變元無效。 – Potatoswatter

+0

好吧,讓我們說我只是想讓它工作,所以我刪除了'std :: forward'。是否有另外一個包裝,我應該使用呢? –

相關問題