2012-08-02 122 views
4

我試圖趕上C++ 11和所有偉大的新功能。我有點卡在lambdas上。Lambdas和std :: function

這是我能得到工作代碼:

#include <iostream> 
#include <cstdlib> 
#include <vector> 
#include <string> 
#include <functional> 

using namespace std; 

template<typename BaseT, typename Func> 
vector<BaseT> findMatches(vector<BaseT> search, Func func) 
{ 
    vector<BaseT> tmp; 

    for(auto item : search) 
    { 
     if(func(item)) 
     { 
      tmp.push_back(item); 
     } 
    } 

    return tmp; 
} 

void Lambdas() 
{ 
    vector<int> testv = { 1, 2, 3, 4, 5, 6, 7 }; 

    auto result = findMatches(testv, [] (const int &x) { return x % 2 == 0; }); 

    for(auto i : result) 
    { 
     cout << i << endl; 
    } 
} 

int main(int argc, char* argv[]) 
{ 

    Lambdas(); 

    return EXIT_SUCCESS; 
} 

我想有是這樣的:

template<typename BaseT> 
vector<BaseT> findMatches(vector<BaseT> search, function <bool (const BaseT &)> func) 
{ 
    vector<BaseT> tmp; 

    for(auto item : search) 
    { 
     if(func(item)) 
     { 
      tmp.push_back(item); 
     } 
    } 

    return tmp; 
} 

基本上我想可能lambda表達式縮小到一個合理的功能的子集。 我錯過了什麼?這甚至有可能嗎?我正在使用GCC/G ++ 4.6。

+1

如果你想做什麼(即使用'std :: function'),你會得到什麼錯誤?也不是說GCC沒有完全支持一些C++ 11的支持,即使在GCC 4.7中也不支持4.6。 – 2012-08-02 09:07:54

+0

你的第二個代碼示例看起來不錯;你會得到什麼錯誤? – ecatmur 2012-08-02 09:10:54

+1

模板只允許精確匹配,因此您無法將lambda函數傳遞給期望使用'std :: function'的函數模板。而且,'function'構造函數不需要拒絕那些實際上不匹配'function'簽名的參數,所以實際上並沒有用於縮小範圍。 – JohannesD 2012-08-02 09:15:25

回答

8

Stephan T. Lavavej解釋了爲什麼這在this video中不起作用。基本上,問題是編譯器試圖從推導BaseT兩個參數std::vector參數std::function。 C++中的lambda是而不是,它的類型爲std::function,它是一個未命名的唯一的非聯合類型,如果它沒有捕獲列表(空[]),它可轉換爲函數指針。另一方面,可以從任何可能的可調用實體類型(函數指針,成員函數指針,函數對象)創建一個std::function對象。

請注意,我個人不明白爲什麼要將傳入的函數限制爲該特定的簽名(除了通過多態函數包裝的間接尋址,如std::function,遠不如直接調用一個仿函數(甚至可以內聯)),但這裏有一個工作版本。基本上,它禁止在std::function部分參數推導,並只從std::vector參數推導BaseT

template<class T> 
struct Identity{ 
    typedef T type; 
}; 

template<typename BaseT> 
vector<BaseT> findMatches(vector<BaseT> search, 
    typename Identity<function<bool (const BaseT &)>>::type func) 
{ 
    vector<BaseT> tmp; 

    for(auto item : search) 
    { 
     if(func(item)) 
     { 
      tmp.push_back(item); 
     } 
    } 

    return tmp; 
} 

另一種可能的方法是將不直接限制函子類型,但間接地通過SFINAE:

template<class T, class F> 
auto f(std::vector<T> v, F fun) 
    -> decltype(bool(fun(v[0])), void()) 
{ 
    // ... 
} 

Live example on Ideone.

如果fun未接受類型爲T&的參數,或者返回類型不能轉換爲bool,則該功能將從過載集中刪除。 , void()使得f的返回類型void

+3

因此,爲了澄清,OP的代碼示例失敗了,因爲編譯器試圖對'std :: function'參數做模板參數推導? – ecatmur 2012-08-02 09:26:03

+0

@ecatmur:正確。 – Xeo 2012-08-02 09:26:55

+0

不需要'Identity':只需使用'std :: common_type :: type'。 – 2012-08-02 09:27:35

0

正如其他海報所揭示的,這是std :: function的一個模板參數演繹。

使第二個代碼片段工作的一種直觀方式是在調用模板函數時添加您的基本類型:findMatches<int>

使用的std :: is_convertible通過XEO未提及的另一種方法:

template<typename BaseT, typename FUNC> 
vector<BaseT> findMatches(vector<BaseT> search, function <bool (const BaseT &)> func) 
{ 
    static_assert(std::is_convertible<FUNC, function<bool (const BaseT &)> >::value, "func must be convertible to ..."); 

    vector<BaseT> tmp; 

    for(auto item : search) 
    { 
     if(func(item)) 
     { 
      tmp.push_back(item); 
     } 
    } 

    return tmp; 
} 

它避免包裝的λ成的std ::功能,並提供了更清潔的錯誤消息。

相關問題