2012-08-02 4 views
4

저는 C++ 11과 모든 훌륭한 새로운 기능을 따라 잡으려고합니다. 나는 람다에 조금 붙어있다.Lambdas and std :: function

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; 
} 

은 기본적으로 내가 분별에 가능 람다를 좁히려 :

#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; 
} 

내가하고 싶은 것은이된다

여기에 내가 일을 얻을 수 있었다 코드는 기능들의 부분 집합. 내가 무엇이 누락 되었습니까? 이것은 가능한가? 저는 GCC/G ++ 4.6을 사용하고 있습니다.

+1

원하는 경우 (예 :'std :: function'을 사용하여) 어떤 오류가 발생합니까?또한 일부 C++ 11 지원은 GCC에서 완전히 지원되지 않으며 GCC 4.7에서는 4.6보다 훨씬 적습니다. –

+0

두 번째 코드 샘플이 좋아 보인다. 어떤 오류가 발생합니까? – ecatmur

+1

템플릿은 정확히 일치하는 것을 허용하기 때문에'std :: function'을 기대하는 함수 템플릿에 람다를 전달할 수 없습니다. 게다가,'function' 생성자는 실제로'function' 서명과 일치하지 않는 인수를 거부 할 필요가 없기 때문에, 실제로 그것을 좁히는 것은 유용하지 않습니다. – JohannesD

답변

8

Stephan T. Lavavej가 this video에서 작동하지 않는 이유를 설명합니다. 기본적으로 문제는 컴파일러가 BaseT에서std::vectorstd::function 매개 변수 모두에서 추론하려고 시도한다는 것입니다. C++의 람다는 이 아니고 std::function 타입의이 아니라 캡쳐리스트 (빈 [])가없는 경우 함수 포인터로 변환 가능한 이름없는 고유 한 비 유니온 타입입니다. 반면에 std::function 객체는 가능한 모든 유형의 호출 가능 엔터티 (함수 포인터, 멤버 함수 포인터, 함수 개체)에서 만들 수 있습니다.

들어오는 펑터를 특정 서명으로 제한하려는 이유를 개인적으로 이해하지 못합니다 (std::function과 같은 다형 함수 래퍼를 통한 간접 참조는 직접 서명보다 훨씬 비효율적입니다. functor (심지어 인라인 될 수도 있음)를 호출합니다.)하지만 여기서는 작동하는 버전입니다. 기본적으로, 그것은 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; 
} 

Live example on Ideone.

또 다른 가능한 방법은 SFINAE을 통해 직접 펑터의 유형을 제한하지 수 있지만 간접적 것입니다 :

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

Live example on Ideone.

funT& 유형의 인수를 사용하지 않거나 반환 유형을 bool으로 변환 할 수없는 경우이 함수는 오버로드 집합에서 제거됩니다. , void()f의 반환 유형을 void으로 만듭니다.

+3

컴파일러가'std :: function' 인수에 템플릿 인자 공제를 시도하기 때문에 OP의 코드 샘플이 실패합니다. – ecatmur

+0

@ecatmur : 맞습니다. – Xeo

+0

'Identity'가 필요 없습니다. 단지'std :: common_type :: type'을 사용하십시오. –

0

다른 포스터에서 밝혀진 바와 같이, 이것은 std :: function에 대한 템플릿 인수 공제입니다.

두 번째 코드 단편 작업을 수행하는 직관적 인 방법 중 하나는 템플릿 함수를 호출 할 때 기본 유형을 추가하는 것입니다 : findMatches<int>.

표준 : 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; 
} 

.

관련 문제