2017-01-29 3 views
18

다음 코드가 (C++ 11 모드에서) 컴파일되지 않는 이유는 무엇입니까?템플릿 함수 매개 변수로 lambda 전달

prog.cc:9:5: error: no matching function for call to 'qux' 
    qux(ts, [](const T&) { return 42; }); 
    ^~~ 
prog.cc:4:6: note: candidate template ignored: could not match 'To (const From &)' against '(lambda at prog.cc:9:13)' 
void qux(const std::vector<From>&, To (&)(const From&)) { } 
    ^

그러나이 매개 변수와 일치 할 수없는 이유는 설명하지 않습니다

#include <vector> 

template<typename From, typename To> 
void qux(const std::vector<From>&, To (&)(const From&)) { } 

struct T { }; 

void foo(const std::vector<T>& ts) { 
    qux(ts, [](const T&) { return 42; }); 
} 

오류 메시지입니다. intTToFrom 대체 내가 qux 비 템플릿 함수를 한 경우

, 그것은 컴파일합니다.

+2

우선'qux'는 아무 것도 반환하지 않으므로'auto bar = qux ... '를 컴파일하면 안됩니다. – nbro

+0

@nbro 이는 당면의 문제와 아무런 관련이 없습니다. – emlai

+2

너무 많이 알고 있으면 질문하지 않을 것입니다. 어쨌든, 이유도 모르기 때문에 upvoted. – nbro

답변

13

람다 함수는 일반적인 함수가 아닙니다. 각 람다는 자신의 타입이 이고 어떤 경우에도To (&)(const From&)이 아닙니다.
비 캡처 람다 사용하여 귀하의 경우 To (*)(const From&)에 붕괴 할 수

#include <vector> 

template<typename From, typename To> 
void qux(const std::vector<From>&, To (&)(const From&)) { } 

struct T { }; 

void foo(const std::vector<T>& ts) { 
    qux(ts, *+[](const T&) { return 42; }); 
} 

int main() {} 
:

qux(ts, +[](const T&) { return 42; }); 
코멘트에서 언급 한 바와 같이

, 당신은 람다에서 그것을 얻기 위해 할 수있는 최선은 이것이다


참고 : 반환 문제의 유형과 유형을 추론하는 것이 실제 문제에서 필수적이라고 가정했습니다. 그렇지 않으면 쉽게 일반 호출 가능한 객체로 전체 람다를 추론하고 직접 사용할 수 있으므로 아무 것도 썩힐 필요가 없습니다.

+1

감사! 람다 앞에'* +'를 붙이면 ref로 넘겨 줄 수 있습니다. C++을 사랑해야 해 ... – emlai

+0

@tuple_cat 좋은 캐치, 대답에 당신의 코멘트를 덧붙이겠다. – skypjack

+2

사실'*'만으로 충분합니다.'* +'는 필요 없습니다. – emlai

10

당신이 추론 To 유형을 사용할 필요가없는 경우, 당신은 단지 전체 매개 변수의 유형을 추론 할 수 있습니다 : 만약 내가 잘못

template<typename From, typename F> 
void qux(const std::vector<From>&, const F&) { } 
+0

예, 권장되는 방법입니다. – milleniumbug

+3

'std :: result_of' – milleniumbug

+1

이것은 닌자를'* +'로 바꾸는 것보다 훨씬 낫습니다 ... –

6

저를 수정하지만, 템플릿 매개 변수 공제는 정확한 유형을 추론를 가능한 전환을 고려하지 않고

결과 qux 기능에 대한 참조를 기대하기 때문에 컴파일러는 To (&)(const From&)에 대한 ToFrom을 추론 할 수는 없지만 자신의 유형이 람다를 제공합니다.

2

To을 추측하기 위해 컴파일러를 사용할 기회가 전혀 없습니다. 따라서 명시 적으로 지정해야합니다.

또한 여기서 람다는 포인터로 전달되어야합니다.

마지막으로,이 버전은 확인 컴파일 : 당신은 암시 적 형식 변환을 모두 기다리고있어

template<typename From, typename To> 
void qux(const std::vector<From>&, To (*)(const From&)) { } 

struct T { }; 

void foo(const std::vector<T>& ts) { 
    qux<T,int>(ts,[](const T&) { return 42; }); 
} 
2

및 발생하는 템플릿 유형 공제 (익명의 함수 객체 타입에서하는 참조 유형을 기능). 그러나 you can't have both, 적합한 변환 순서를 찾으려면 대상 유형을 알아야합니다.

1

그러나 매개 변수와 일치하지 않는 이유는 설명하지 않습니다.

템플릿 공제는 유형을 정확하게 일치 시키려고합니다. 유형을 추론 할 수없는 경우 공제가 실패합니다. 전환은 결코 고려되지 않습니다.이 식에서

:

qux(ts, [](const T&) { return 42; }); 

람다 식의 형태는 어떤 고유, 이름 유형이다. 그 유형이 무엇이든, 그것은 분명히 To(const From&)이 아닙니다 - 그래서 공제가 실패합니다. intTToFrom 대체 내가 qux 비 템플릿 함수를 한 경우


, 그것은 컴파일합니다.

사실이 아닙니다. 그러나 인수가 참조 0보다 작동하는 포인터 이었으면 함수가 될 것입니다. 이것은 캡처가없는 람다가 암시 적으로 동등한 함수 포인터 유형으로 변환되기 때문입니다. 이 전환은 공제의 컨텍스트 외부에서 허용됩니다.

template <class From, class To> 
void func_tmpl(From(*)(To)) { } 

void func_normal(int(*)(int)) { } 

func_tmpl([](int i){return i; }); // error 
func_tmpl(+[](int i){return i; }); // ok, we force the conversion ourselves, 
            // the type of this expression can be deduced 
func_normal([](int i){return i; }); // ok, implicit conversion 

이이 실패한 이유 같은 이유입니다 :

template <class T> void foo(std::function<T()>); 
foo([]{ return 42; }); // error, this lambda is NOT a function<T()> 

는 그러나이 작업이 성공 :

void bar(std::function<int()>); 
bar([]{ return 42; }); // ok, this lambda is convertible to function<int()> 

선호되는 방법은 호출의 유형을 추론하는 것 및 std::result_of을 사용하여 결과 선택 :

template <class From, 
    class F&&, 
    class To = std::result_of_t<F&&(From const&)>> 
void qux(std::vector<From> const&, F&&); 

이제 람다, 함수 또는 함수 객체를 잘 전달할 수 있습니다.

관련 문제