2016-10-25 16 views
7

Załóżmy, że mam std::tuple:Jak mogę sprawdzić, czy element istnieje w krotce?

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

Teraz chcę znaleźć, jeśli func Zwraca true dla każdego elementu w lambda, gdzie func pewne lambda, np

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

Jak mogę zrobić to? Zauważ, że Types... może być duży, więc nie chcę iterować ponad wszystkich elementów za każdym razem.

+0

Możesz [rozpakować tup le do wywoływania funkcji variadic-template] (http://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments), które sprawdzają każdy argument. –

+1

Wydaje się być duplikatem [tego] (http://stackoverflow.com/questions/1198260/iterate-over-tuple). – m8mble

+0

@ m8mble Dodałem linię, aby podkreślić, dlaczego jest inaczej (w zasadzie jest to różnica między 'for_each' i' any_of' - zatrzymanie na elemencie, gdy go znajdziesz). – arman

Odpowiedz

4
#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

+0

w tym przypadku może to być po prostu 'args', ale ogólnie, jeśli, powiedzmy, można wpisać' std :: move (myTuple) 'w' apply', to uważam, że forwarding może być przydatny –

+1

Wspomnę o tym, że '' std :: apply' to C++ 17. – skypjack

+2

@skypjack więc są wyrażenia fold – krzaq

2

Oto C++ 14 Rozwiązanie:

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

+0

dobre rozwiązanie, ale nie jestem pewien, czy istnieje jakikolwiek wzrost czasu kompilacji przy użyciu 'std :: integer_sequence' podczas tworzenia wystąpienia' any_of_impl' dla każdego indeksu elementów krotki, nie? –

+0

@ W.F. Już miałem odpowiedzieć, że potrzebuję tego, ponieważ tuple może mieć powielone typy i 'get ' nie zadziałałoby, ale z tym rekursywnym zwarciem nie potrzebuję tego. Zaktualizuję lepszą wersję, dzięki. – krzaq

0

A oto trochę retro C++ 11 Rozwiązanie:

#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; 
} 
Powiązane problemy