2012-08-02 88 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 ::功能,并提供了更清洁的错误消息。

相关问题