3

I'm playing around with C++14 lambdas (well just lambdas in general really) and I have a function (pipeline) I'm trying to write. The premise is that it'll take a unit lambda and an array of unary lambdas that it'll then run on the unit and produce a new unit to send into the next in the pipeline until you get through the last lambda and return the final unit. my current code is:

auto pipeline = [](auto u, auto callbacks[]){
  for(int i = 0; i<sizeof(callbacks)/sizeof(callbacks[0]);i++){
     u = bind(u,callbacks[i]);
  }
  return u;
};

The current issue is that clang is kicking back on the array saying:

testFuture.cpp:183:111: error: no matching function for call to object of type 'func::<lambda at ./func.hpp:30:19>'
  cout<<"pipeline(unit(10),{addf(4),curry(mul,2)}):"<<bind(unit(bind(unit(10))(addf(4))))(curry(mul,2))<<"|"<<pipeline(unit(10),{{addf(4),curry(mul,2)}})()<<endl;
                                                                                                              ^~~~~~~~
./func.hpp:30:19: note: candidate template ignored: couldn't infer template argument '$auto-0-1'
  auto pipeline = [](auto u, auto callbacks[]){
                  ^
1 error generated.

Is this simply not possible with lambdas? Do I need to whip out std::function? Am I just going about this the wrong way?

0

1 Answer 1

7

Taking a step back, you’re attempting to perform a (left) fold over a sequence of values. Because in C++ each closure has a unique type, you want to make that fold over a tuple, not an array. As an added benefit, we will be more general and accept functors with any return type, which we couldn’t if e.g. we used std::function to emulate arrow types.

#include <utility>      // std::forward, std::integer_sequence
#include <type_traits>  // std::remove_reference_t
#include <tuple>        // tuple protocol, e.g. std::get, std::tuple_size

namespace detail {

template<typename Functor, typename Zero, typename Tuple, typename Int>
Zero foldl(Functor&&, Zero&& zero, Tuple&&, std::integer_sequence<Int>)
{ return std::forward<Zero>(zero); }

template<typename Functor, typename Zero, typename Tuple, typename Int, Int Index, Int... Indices>
decltype(auto) foldl(Functor&& functor, Zero&& zero, Tuple&& tuple, std::integer_sequence<Int, Index, Indices...>)
{ return detail::foldl(
        functor
        , functor(std::forward<Zero>(zero), std::get<Index>(std::forward<Tuple>(tuple)))
        , std::forward<Tuple>(tuple)
        , std::integer_sequence<Int, Indices...> {}); }

} // detail

template<typename Functor, typename Zero, typename Tuple>
decltype(auto) foldl(Functor&& functor, Zero&& zero, Tuple&& tuple)
{
    return detail::foldl(
            std::forward<Functor>(functor)
            , std::forward<Zero>(zero)
            , std::forward<Tuple>(tuple)
            , std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>()
            );
}

You haven’t told us what bind is supposed to achieve, but here’s an example involving reverse composition of functions. (Included is a limited implementation of integer_sequence and friends as they don’t appear to be available on Coliru — type traits aliases are missing as well.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.