2017-12-22 13 views
0

전달 된 functor에 따라 템플릿 매개 변수를 제약하고 싶습니다. 일부 컨테이너 유형에서,이 FoldLeft 기능을 고려전달 된 functor에 따른 제약 템플릿 매개 변수

template<typename F, typename R> 
R FoldLeft(F&& functor, R initialValue) { 
    R r = initialValue; 
    /* assume that this is a range of uint64_t's */ 
    while (first != last) { 
     r = std::forward<F>(functor)(r, *(first++)); 
    } 
    return r; 
} 

이 기능은 다음과 같이 호출 할 수 있습니다 : 여기

auto sum = FoldLeft([](uint64_t i, auto& e) { return e + i; }, 0); 

이 문제가 R가에 0을있는 initialValue 매개 변수, 추론된다는 것이다 이 경우 따라서 int이됩니다. 마찬가지로 decltype(sum)int이됩니다.

람다 또는 다른 호출 가능 유형 일 수있는 functor의 반환 유형으로 R을 추려 놓고 싶습니다. 이미이 오류로 실행 항상 this answer에서 방법을 사용했지만 :

error: decltype cannot resolve address of overloaded function 
struct function_traits 
     ^~~~~~~~~~~~~~~ 
note: substitution of deduced template arguments resulted in errors seen above 

(링크 된 답변에서 복사 fuction_traits) 내 시도의 코드 :

template<typename T> 
using LamRet = typename function_traits<T>::result_type; 

template<typename F> 
LamRet<F> FoldLeft(F&& functor, LamRet<F> initialValue) { 
    LamRet<F> r = initialValue; 
    /* assume that this is a range of uint64_t's */ 
    while (first != last) { 
     r = std::forward<F>(functor)(r, *(first++)); 
    } 
    return r; 
} 
+0

'첫 번째/마지막'에서이 정보를 얻는 것이 훨씬 더 쉽습니다. 제안하는 것보다 쉽습니다. – Justin

+1

람다에서 매개 변수로'auto'를 사용하지 않는 것이 좋다면, 코드는 작동 할 것입니다. – Justin

답변

3

기능 특성은 거의 쓸모가, C++에서 호출 함수는 함수 특성과 같은 특성을 갖고 있지 않기 때문에 바인딩을 사용합니다.

호출 가능 항목의 하위 집합 만 이러한 특성을 갖습니다. 또한 C++ 14 및 C++ 17 스타일의 람다를 많이 쓰면할수록 호출 대상이 적습니다.

반환 값을 결정할 때 반복되는 형식이 무엇인지 알아야합니다. 그런 다음 decltype(lambda(argument, iterated_type)) (result_of_t 또는 invoke_result_t 템플릿 유형으로 기록 될 수도 있음)을 검사하십시오.

가정하여 반복 된 유형은 T이며, 당신의 주장은 A입니다 :

template<class F, class A> 
using LamRet = std::decay_t<std::result_of_t<F&&(A&&, T&)>>; 

그런 다음 우리가 우리의 람다 인수 유형을 확인할 수 있습니다

template<class F, class A> 
using LamArgGood = std::is_convertible< A&&, LamRet<F, A> >; 

template<class F, class A> 
using LamRetGood = std::is_convertible< LamRet<F, A>, LamRet< F, LamRet<F, A > >; 

하는 반복의 반환 유형이 작동하는지 확인합니다.

template<class F, class A, 
    class dA = std::decay_t<A>, 
    std::enable_if_t< LamArgGood<F, dA>{} && LamRetGood<F, dA>{}, bool> =true 
> 
LamRet<F, dA> FoldLeft(F&& functor, A&& initialValue) { 
    LamRet<F, dA> r = std::forward<A>(initialValue); 
    /* assume that this is a range of uint64_t's */ 
    while (first != last) { 
    r = std::forward<F>(functor)(r, *(first++)); 
    } 
    return r; 
} 

이것은 적절하지 않지만 99 %의 유형 오류를 잡아냅니다. (내가 반복을 구성하지 않고 할당하고, 이 아니라 A&&LamRet으로 변환).

+0

좋은 대답, 1 % 유형의 오류가 잡히지 않도록 유도 할 수있는 것은 무엇입니까? – nyronium

+0

@nyron 내가 그랬어? 예는 같은 단락의 괄호 안에 나와 있습니다. – Yakk

+1

또는 더 많은 단어를 원하십니까? 할당 할 수 없지만 구성 가능한 유형이 반복됩니다. 수정하기 쉽습니다 (한 곳에서 도미넌트 특성으로 대치 가능 형질을 대체하십시오). 반환 형식으로 이상한 복사/이동 생성자 연산이 포함 된 인수.위의 내용이 실패하는 예를 찾기 위해 놀아야 할 것입니다. 반환 유형을 자체에 포함하십시오. 그리고 만약 리턴 타입 binop이 이상하게 생긴다면 리턴 타입으로 변환하는 한 그 사실을 무시합니다. (하나의 반복 선택은 임의적입니다) – Yakk