2013-01-08 3 views
0

나는 나를 위해 잘 작동하는 기능했습니다 :설정 일반 반환 형식

template <typename __container, typename __callback = std::function < 
    void (typename __container::value_type, typename __container::value_type)> 
> 
auto reduce(__container &&container, __callback &&callback) -> 
decltype(__container::value_type); 

그러나 나는 점점 오전 :

template <typename __container, typename __callback = std::function < 
    void (typename __container::value_type, typename __container::value_type)> 
> 
int reduce(__container &&container, __callback &&callback) 
{ 
    auto current = container.begin(); 

    for (auto value : container) 
     *current = callback(*current, value); 

    return *current; 
}; 


int result = functional::reduce(vector, [](const int current, const int next) -> int { 
    return current + next; 
}); 

std::cout << result; // 10 

그리고 지금, 나는 하나를 통합하는거야 다음 오류 :

reduce.cpp:61:9: error: no matching function for call to 'reduce' 
int i = reduce(vector, [](const int current, const int next) -> int { 
     ^~~~~~~~~~~~~~~~~~ 
reduce.hpp:69:7: note: candidate template ignored: substitution failure [with __container = std::__1::list<int, std::__1::allocator<int>> &, __callback = <lambda at 
     nott.cpp:61:36>] 
     auto reduce(__container &&container, __callback &&callback) -> decltype(__container::value_type) 
      ^
1 error generated. 
make: *** [build] Error 1 

어떻게 일반 반환 유형을 설정할 수 있습니까?

UPDATE :

template <typename __container, typename __callback> 
auto reducef(const __container& input, __callback callback) -> 
decltype(callback(std::declval<typename __container::value_type>(), std::declval<typename __container::value_type>())) 
{ 
    decltype(
     callback(
      std::declval<typename __container::value_type>(), 
      std::declval<typename __container::value_type>() 
     ) 
    ) result{}; 

    return std::accumulate(input.begin(), input.end(), result, callback); 
}; 
+1

는'value_type' 당신은'decltype'를 사용할 필요가 없습니다, 이미 유형 : 여기에, (스타일 손에 문제가 아니므로) 당신이 무엇을했다에 가까운 코드를 유지하는 것은 작업 버전입니다 그것으로. 당신은'typename' 생각이 필요합니다. –

+7

두 개의 밑줄 (예 :'__container')로 시작하는 이름은 구현을 위해 예약되어 있으므로 사용하지 마십시오. – ipc

+4

이 코드의 수정이 끝나면 다용도가 아닌'std :: accumulate' 버전으로 끝날 것입니다. –

답변

4

이 서명이 잘못은 :

auto reduce(__container &&container, __callback &&callback) -> 
decltype(__container::value_type); 

value_type 유형입니다 당신은 그것을 decltype. 이것은 decltype(int)과 같습니다. 그러나 __container::value_type은 컴파일러가 value_type이 유형이라는 것을 알지 못하기 때문에 작동하지 않습니다.

auto reduce(__container &&container, __callback &&callback) -> 
typename __container::value_type; 

을 개선 할 수있는 몇 가지 더 가지가있다 : 당신은 그것을 줄이기 위해 컴파일러의 전면 요소를 수정 당신은 typename을 사용하여이 명시 적으로 확인해야합니다. 난 당신이 이런 식으로 뭔가를하고 싶은 생각 :

auto current = *container.begin(); // added * 

for (auto value : container) 
    current = callback(*current, value); // removed * 

return current; // removed * 

또 다른 버그가 있습니다 : 첫 번째 값이 두 배 감소됩니다.

assert(!container.empty()); 
auto current = *container.begin(); 

for (auto it=container.begin()+1; it!=container.end(); ++it) 
    current = callback(current, *it); 

return current; 

또한 개선 : 사용 반복자 대신 범위 :

template <typename Iter, typename Callback> 
T reduce(Iter start, Iter end, Callback&& F) 
{ 
    assert(start != end); 
    auto current = *start; 
    while (++start != end) 
     current = callback(current, *it); 
    return *current; 
}; 

다음 질문 : 왜 빈 범위를 수락하지의 제한? 초기 값을 사용하십시오.

template <typename Iter, typename T, typename Callback> 
T reduce(Iter start, Iter end, T init, Callback&& F) 
{ 
    while (start != end) 
     init = callback(init, *it++); 
    return init; 
}; 

그리고, 놀랍게도,이 정확히 std::accumulate의 정의입니다.

+0

감사합니다. 내 소식을 업데이트했습니다. –

1

다른 사람들이 언급했듯이 decltype은 필요하지 않습니다. auto도 필요하지 않습니다.

#include <iostream> 
#include <vector> 

template <typename Container, typename Callback> 
typename Container::value_type reduce(Container &container, Callback &&cb) { 
    auto current = container.begin(); 

    for (auto value : container) 
     *current = cb(*current, value); 

    return *current; 
} 

int main() { 
    std::vector<int> v = {1, 2, 3}; 

    int result = reduce(v, [](const int current, const int next) -> int { 
     return current + next; 
    }); 

    std::cout << "result = " << result << std::endl; 
}