Skip to content

Instantly share code, notes, and snippets.

@insooth
Created October 18, 2019 12:00
Show Gist options
  • Save insooth/5591e44232e4ba1aa1400ae450899579 to your computer and use it in GitHub Desktop.
Save insooth/5591e44232e4ba1aa1400ae450899579 to your computer and use it in GitHub Desktop.
// see LICENSE on insooth.github.io
#include <cstddef> // size_t
#include <tuple> // tuple, tuple_element
#include <type_traits> // disjunction
#include <utility> // {make_,}index_sequence
#include <iostream>
// Find within a Tuple using given Predicate.
//
// Result is a type that exposes an index of the found item,
// the result of the applied predicate (shall be true for found item),
// and the found type itself.
template<class Tuple, template<class> class Predicate>
class find_in_if
{
template<
class T // actual type
, template<class> class P // predicate
, std::size_t I // index within a tuple
>
struct box
{
using type = T;
static constexpr std::size_t index = I;
static constexpr bool value = P<T>::value; // disjunction uses this
};
template<class, class = void>
struct find_in_if_impl;
template<std::size_t... Is, class _>
struct find_in_if_impl<std::index_sequence<Is...>, _>
{
using type =
std::disjunction<
box<std::tuple_element_t<Is, Tuple>, Predicate, Is>...
>;
};
public:
using type =
typename find_in_if_impl<
std::make_index_sequence<std::tuple_size_v<Tuple>>
>::type;
};
template<class Tuple, template<class> class Predicate>
using find_in_if_t = typename find_in_if<Tuple, Predicate>::type;
// for exposition only -- partially applied is_same, in general can be any predicate
template<class T> using is_int = std::is_same<T, int>;
template<class T> using is_bool = std::is_same<T, bool>;
template<class T> using is_float = std::is_same<T, float>;
int main()
{
using foundI = find_in_if_t<std::tuple<int, bool, float>, is_int>;
using foundB = find_in_if_t<std::tuple<int, bool, float>, is_bool>;
using foundF = find_in_if_t<std::tuple<int, bool, float>, is_float>;
std::cout << "{ " << std::boolalpha << is_int<foundI::type>::value
<< ", " << foundI::index
<< ", " << foundI::value << " }\n";
std::cout << "{ " << std::boolalpha << is_bool<foundB::type>::value
<< ", " << foundB::index
<< ", " << foundB::value << " }\n";
std::cout << "{ " << std::boolalpha << is_float<foundF::type>::value
<< ", " << foundF::index
<< ", " << foundF::value << " }\n";
return 0;
}
/*
http://coliru.stacked-crooked.com/a/9bb69b881f7a7f5f
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
{ true, 0, true }
{ true, 1, true }
{ true, 2, true }
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment