Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the return type of a lambda, reduce function in C++11

Tags:

c++

c++11

I'm trying to implement a reduce function but I don't know how to take the return type of the lambda:

template <typename IT, typename F, typename OT = IT>
auto reducef(const IT& input, F func) -> decltype(func(IT::value_type))
{
    decltype(func(typename IT::value_type)) result = {}; 
    return std::accumulate(input.begin(), input.end(), result, func);
}

Compiler output is the following:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:37:80: error: no matching function for call to ‘reducef(std::vector<int>&, main(int, char**)::<lambda(const int&, const int&)>)’
test.cpp:37:80: note: candidate is:
test.cpp:22:6: note: template<class IT, class F, class OT> decltype (func(IT:: value_type)) reducef(const IT&, F)
test.cpp:22:6: note:   template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class IT, class F, class OT> decltype (func(IT:: value_type)) reducef(const IT&, F) [with IT = std::vector<int>; F = main(int, char**)::<lambda(const int&, const int&)>; OT = std::vector<int>]’:
test.cpp:37:80:   required from here
test.cpp:22:6: error: dependent-name ‘IT:: value_type’ is parsed as a non-type, but instantiation yields a type
test.cpp:22:6: note: say ‘typename IT:: value_type’ if a type is meant

Extended use case:

template <typename IT, typename F, typename OT = IT>
OT mapf(const IT& input, F func)
{
    OT output;
    output.resize(input.size());
    std::transform(input.begin(), input.end(), output.begin(), func);
    return output;
}

template <typename IT, typename F, typename OT = IT>
auto reducef(const IT& input, F func) -> decltype(func(IT::value_type))
{
    typename IT::value_type result = {};
    return std::accumulate(input.begin(), input.end(), result, func);
}


int main(int argc, char *argv[])
{
    vector<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    auto v2 = mapf(v1, [](const int& i) { return i+1;});
    for (const auto& i : v2)
    {     
        cout << i << endl;  
    }   
    cout << reducef(v1, [](const int& i, const int& j) -> int { return i + j; }) << endl;
}            
like image 305
piotr Avatar asked Nov 19 '12 20:11

piotr


1 Answers

I think you want to declare you return type as something like

decltype(func(std::declval<typename IT::value_type>(),
              std::declval<typename IT::value_type>()))

Here is a complete testcase:

#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>

template <typename IT, typename F, typename OT = IT>
auto reducef(const IT& input, F func)
    -> decltype(func(std::declval<typename IT::value_type>(),
                     std::declval<typename IT::value_type>()))
{
    decltype(func(std::declval<typename IT::value_type>(),
                  std::declval<typename IT::value_type>())) result{};
    return std::accumulate(input.begin(), input.end(), result, func);
}

int main()
{
    std::vector<int> values;
    reducef(values, [](int a, int b) { return a + b; });
}
like image 93
Dietmar Kühl Avatar answered Sep 28 '22 09:09

Dietmar Kühl