2017-09-25 78 views
3

有人在堆棧溢出中寫了一個有趣的方式來將lambda或函子捕獲到自己的類中。我試圖簡化它,我想我已經接近了,但遇到了一些麻煩。他們的例子是:如何使用可變參數製作模板函數的返回類型

// OT => Object Type 
// RT => Return Type 
// A ... => Arguments 

template<typename OT, typename RT, typename ... A> 
struct lambda_expression { 
    OT _object; 
    RT(OT::*_function)(A...)const; // A pointer to a member function, 
            // specifically the operator() 

    lambda_expression(const OT & object) // Constructor 
     : _object(object), 
      _function(&decltype(_object)::operator()) {} // Assigning the function pointer 

    RT operator() (A ... args) const { 
     return (_object.*_function)(args...); 
    } 
}; 

基本上,這可以讓你去:

int captureMe = 2; 
auto lambda = [=](int a, int b) { return a + b + captureMe;}; 
lambda_expression<decltype(lambda), int, int, int>(lambda); 

我正在努力簡化這一點,並認爲包含在lambda_expression類指針就沒有必要了,因爲你可以調用函數對象本身,而不是調用指向operator()的指針。所以,我想這一點:

template <typename OT, typename ... Args> // No Return type specified 
struct lambdaContainer 
{ 
    lambdaContainer(OT funcObj) : funcObj(funcObj){ } 
    OT funcObj; // No pointer, just the function object. 

    auto operator()(Args... args) 
    { 
     return funcObj(args...); // Call the function object directly 
    } 
}; 

然後是這樣的:

int captureMe = 2; 
auto lambda = [=](int a, int b) { return a + b + captureMe; }; 

lambdaContainer<decltype(lambda), int, int> lam(lambda); 

auto i = lam(1, 1); 
// i = 4; 

我在哪裏寫了一行:

auto operator()(Args... args) 
    { 
     return funcObj(args...); 
    } 

顯然:

decltype(auto) operator()(Args... args) //works in C++14 apparently. 

但是我還是沒有auto關鍵字,我在這樣做時失敗了,我想了解Args ...的工作原理。我嘗試過:

decltype(funObj(Args...) operator()(Args... args) // this failed 
decltype(OT(Args...) operator() (Args... args) // this failed 
auto operator() (Args... args) -> decltype(funcObj(Args...)) // this failed 
auto operator() (Args... args) -> decltype(OT(Args...)) // this failed 

如何擴展參數以便模板可以推斷返回類型?這隻適用於汽車嗎?

+0

這可能不會正確,但我建議你閱讀[良好的C++書](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list),在特別是一些先進的。在這樣的片段中學習C++非常困難。 –

回答

1

decltype(e)接受一個表達e並評估該表達的類型。您需要提供一個表達代表您的存儲拉姆達的調用:

auto operator()(Args... args) 
    -> decltype(std::declval<OT>()(std::declval<Args>()...)) 

在這種情況下,我使用std::declval創建可用於抵扣的目的,對象的「假實例」 ,而沒有實際調用任何構造函數。

讓我們進一步打破這:

-> decltype(
    std::declval<OT>()   // create a fake instance of `OT` 
    (       // invoke it 
     std::declval<Args>()... // create a fake instance of each argument 
           // type, expanding `Args...` 
    ) 
) 

live example on wandbox


順便說一句,你還是應該std::forward在您的來電funcObj的參數,因爲可能有一些右值引用需要進一步傳播:

auto operator()(Args... args) 
{ 
    return funcObj(std::forward<Args>(args)...); 
} 
+0

這是我會猜到的最後一件事。我正在閱讀declval和std :: forward。 declval我得到了,但另外兩個我不明白。這很有趣,你說declval創建了一個「假」版本的對象。 – Zebrafish

+0

@斑馬魚:'declval'所做的就是返回一個引用類型。由於'std :: declval ()'在未評估的上下文中替換了'T {}',所以我喜歡認爲它是「創建一個假實例」。但它只是返回一個參考:) –

+0

@斑馬魚:我應該進一步澄清什麼東西? –

相關問題