8

Suppose I have a std::tuple:

std::tuple<Types...> myTuple;
// fill myTuple with stuff

Now I want to find if func returns true for any element in the lambda, where func is some lambda, e.g.:

auto func = [](auto&& x) -> bool { return someOperation(x); }

How can I do this? Note that Types... may be large so I don't want to iterate over all elements every time.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
quant
  • 21,507
  • 32
  • 115
  • 211
  • You could [unpack the tuple for calling a variadic-template function](http://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments) which check each argument. – Some programmer dude Oct 25 '16 at 06:51
  • 1
    Seems to be a duplicate of [this](http://stackoverflow.com/questions/1198260/iterate-over-tuple). – m8mble Oct 25 '16 at 06:54
  • @m8mble I've added a line to highlight why this is different (basically it's the difference between `for_each` and `any_of` - stopping on the element when you find it). – quant Oct 25 '16 at 07:08
  • Those don't seem like viable dupe targets. What do you want as a return type? A `variant`? `size_t` index? – krzaq Oct 25 '16 at 07:10
  • @krzaq sorry, I realised my example was poorly worded - I'm actually after `any_of`. I hope this clears it up - the return type is `bool`. – quant Oct 25 '16 at 07:13
  • 2
    `std::apply([](auto&&... args) { return (someOperation(decltype(args)(args)) || ...); }, myTuple);` – Piotr Skotnicki Oct 25 '16 at 07:22
  • @PiotrSkotnicki what's the purpose of `decltype(args)` in this solution? – krzaq Oct 25 '16 at 07:26
  • @krzaq the same as if I used `std::forward` – Piotr Skotnicki Oct 25 '16 at 07:27
  • @PiotrSkotnicki okay, so it's a C function-style static cast? – krzaq Oct 25 '16 at 07:28

3 Answers3

5
#include <tuple>

std::tuple<int, char, double> myTuple{ 1, 'a', 3.14f };

bool result = std::apply([](auto&&... args) {
                           return (someOperation(decltype(args)(args)) || ...);
                         }
                       , myTuple);

DEMO

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
2

Here's a C++14 solution:

template <typename Tuple, typename Pred>
constexpr bool any_of_impl(Tuple const&, Pred&&, std::index_sequence<>) {
    return false;
}

template <typename Tuple, typename Pred, size_t first, size_t... is>
constexpr bool any_of_impl(Tuple const& t, Pred&& pred, std::index_sequence<first, is...>) {
    return pred(std::get<first>(t)) || any_of_impl(t, std::forward<Pred>(pred), std::index_sequence<is...>{});
}

template <typename... Elements, typename Pred, size_t... is>
constexpr bool any_of(std::tuple<Elements...> const& t, Pred&& pred) {
    return any_of_impl(t, std::forward<Pred>(pred), std::index_sequence_for<Elements...>{});
}

live demo

krzaq
  • 16,240
  • 4
  • 46
  • 61
  • good solution, yet I'm not sure if there is any compilation time boost from using `std::integer_sequence` as you instantiate `any_of_impl` for each index of tuple elements, no? – W.F. Oct 25 '16 at 08:34
  • @W.F. I was about to reply that I need this because tuple may have duplicated types and `get` wouldn't work, but with this recursive short-circuiting I don't need this. I'll update with a better version, thanks. – krzaq Oct 25 '16 at 08:40
0

And here's a little bit retro c++11 solution:

#include <iostream>
#include <tuple>

template <class Tuple, class Lambda>
bool any_of(Tuple &&tup, Lambda lambda, std::integral_constant<size_t, std::tuple_size<Tuple>::value> i) {
    return false;
}

template <class Tuple, class Lambda, class I = std::integral_constant<size_t, 0>>
bool any_of(Tuple &&tup, Lambda lambda, I i = {}) {
    return lambda(std::forward<typename std::tuple_element<i, Tuple>::type>(std::get<i>(tup))) ||
           any_of(std::forward<Tuple>(tup), lambda, std::integral_constant<size_t, i+1>{});
}

int main() {
   std::cout << any_of(std::forward_as_tuple(1, 2, 3, 4), [](int&& i) { return i == 2; }) << std::endl;
}
W.F.
  • 13,888
  • 2
  • 34
  • 81