2017-04-25 20 views
1

를 사용하는 경우 유형을 추론하는 데 실패, 내가하는 방법과 같이 작성된 클래스에 대한 과부하가 :컴파일러 그래서 표준 : 기능

bool my_for_each(someIterator begin, someIterator end, bool (*_lambda)(someIterator)); 

void my_for_each(someIterator begin, someIterator end, void (*_lambda)(someIterator)); 

당신이 볼 수 있듯이을, 유일한 차이점은의 서명입니다 전달 된 함수, 즉 반환 유형입니다. 내가 그것을 호출 할 때 위의 코드는 완벽하게 정상적으로 작동하지만 : 나는 my_for_each 함수를 작성하는 경우

my_for_each(iteratorBegin, iteratorEnd, [](someIterator) {; }); // calls void version 

my_for_each(iteratorBegin, iteratorEnd, [](someIterator)->bool {return false; }); // calls bool version 

..., 다음과 같이

bool my_for_each(someIterator begin, someIterator end, std::function<bool(someIterator)> _lambda); 

void my_for_each(someIterator begin, someIterator end, std::function<void(someIterator)> _lambda); 

코드는 내가 함수를 호출하는 경우 컴파일에 실패를 같은 방법 (오버로드 된 함수에 대한 C2668 모호한 호출). 비록 내가 수동으로 함수를 캐스팅했다면 :

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<void(someIterator)>>([](someIterator) {; })); //calls void version 

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<bool(someIterator)>>([](someIterator) -> bool { return false; })); //calls bool version 

코드는 완벽하게 작동합니다. 그래서 궁금해 할 것 :

  1. 표준 함수 포인터 유형 공제가 표준 템플릿보다 "강"한 이유는 무엇입니까?
  2. 매개 변수를 수동으로 캐스팅하지 않고보다 일반적인 버전을 계속 사용할 수있는 해결 방법이 있습니까?

컴파일러는 VS2015입니다.

감사합니다. 좋은 하루 되세요!

+0

FrançoisAndrieux 고정 @, 단지 전사 오류 – Alfaix

+0

은'my_for_each' 함수의 반환 값의 의미는 무엇입니까? –

+0

범위를 형성하는 두 개의 반복자 인 것처럼 보입니다. 반복기를 받아들이고 그것에 무언가를하는 함수입니다. 나는 두 번째 버전 (아마도 and, or 또는 operation 중 하나 일 것임)에있는 모든 'bool'을 가지고 무엇이 완료되고 있는지 확신하지 못한다. –

답변

3

std::function과 람다는 두 번째 예제가 람다 형식에서 std::function으로의 암시 적 변환을 필요로한다는 것을 의미합니다.

문제는 bool를 반환 람다 암시, std::function<bool(T)>std::function<void(T)> 모두 변환 할 수 있습니다, 따라서 모두 과부하가 모호한 오류로 이어지는 전화에 대한 동등하게 유효한 선택이 있다는 것입니다. 올바르게 std::function에 캐스팅하면 모호성이 명시 적으로 해결됩니다.

편집 : 해결 방법은 호출 유형의 종류를 받아들이는 또한 템플릿 과부하를 제공함으로써이 문제를 해결할 수

는, 그 호출 유형에 대한 반환 유형을 추론 자동으로 캐스트를 예비 적. 보편성을 위해 someIterator을 템플릿 인수로 변경했습니다. my_for_each 함수에 대한 구현 세부 정보를 제공하지 않았으므로이 구현을 생략했습니다. voidbool 반환 형식 만 지원하려는 것으로 보였으므로 지원되지 않는 반환 형식이 제공 될 경우 명확한 컴파일러 오류를 생성하기 위해 static_assert을 추가했습니다.

#include <functional> 
#include <type_traits> 

// Implement for std::function<bool(iter)> 
template<class I> 
bool my_for_each(I begin, I end, std::function<bool(I)> lambda); 

// Implement for std::function<void(iter)> 
template<class I> 
void my_for_each(I begin, I end, std::function<void(I)> lambda); 

// Dispatch to the right overload 
template<class T, class I> 
auto my_for_each(I begin, I end, T&& lambda) 
{ 
    using return_type = decltype(lambda(begin)); // Obtain the return type of lambda 
    static_assert(std::is_same<return_type, bool>::value || std::is_same<return_type, void>::value, 
     "my_for_each only accepts function objects that return void or bool"); 
    using function_type = std::function<return_type(I)>; // The type to cast lambda to 
    return my_for_each(begin, end, function_type(std::forward<T>(lambda))); // Preform the cast 
} 
+1

수정 사항은이 대답을 향상시킵니다. – Yakk

+0

그래서 호출 가능한 객체를 사용하려면 매번 static_cast를 사용해야합니다. – Alfaix

+0

@Alfaix 매번 수동으로 캐스팅하지 않으려 고하는 해결책을 편집했습니다. –

2

이유는 비 캡처 람다가 사용 된 인수의 인수를 허용하는 함수 포인터로만 변환 될 수 있기 때문입니다.

한편, std::function에는 모든 것을 허용하는 템플릿 생성자가 있습니다. 그러므로 과부하 해결을 위해 람다 (my_for_each)에서 std::function<bool...>std::function<void ...>을 모두 생성 할 수 있습니다. (그러나 이러한 객체를 만들 수는 없습니다.)