How to Find Out If a Tuple Contains a Type

How do I find out if a tuple contains a type?

#include <tuple>
#include <type_traits>

template <typename T, typename Tuple>
struct has_type;

template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};

template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};

template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};

DEMO

And an additional alias, if the trait itself should be std::true_type or std::false_type :

template <typename T, typename Tuple>
using tuple_contains_type = typename has_type<T, Tuple>::type;

How to check if a tuple contains an element in Python?

You use in.

if element in thetuple:
#whatever you want to do.

Check if an item inside a tuple contains a specific method

If you don't have access to requires yet, then you will have to make use of SFINAE and write a type-trait for detecting whether initialize() is a callable member function.

This can be done with std::void_t, albeit a little awkwardly:

#include <type_traits> // std::void_t
#include <utility> // std::declval

template <typename T, typename = void>
struct has_initialize_impl : std::false_type {};

template <typename T>
struct has_initialize_impl<T,
std::void_t<decltype(std::declval<T&>().initialize())>
> : std::true_type {};

template <typename T>
inline constexpr auto has_initialize = has_initialize_impl<T>::value;

The above trait checks if any mutable reference T& can call a function named initialize(). If the expression is well-formed, then has_initialized evaluates to true; otherwise, it evaluates to false.

This can then be used with the rest of your code with little changes:

template <class... Args>
struct CustomTuple : std::tuple<Args...> {
// Calls "initialize() for each item inside the tuple if that function exists"
template <std::size_t I = 0>
auto initialize() {
// Note: no need to construct a temporary/unused 'item' type,
// we can just use 'tuple_element' here to get the type
using element_type = typename std::tuple_element<I, std::tuple<Args...>>::type;

if constexpr (has_initialize<element_type >) {
std::get<I>(*this).initialize();
}
if constexpr (I + 1 != sizeof...(Args)) {
initialize<I + 1>();
}
}
};

Live Example


If you think you might have a lot more cases where you need to detect functionality, but still won't have C++20 requires support, then it might be worthwhile looking into adding the "detected"-idiom + boilerplate into your code, which can be found on cppreference.

This behaves identically to what std::void_t does, but is more convenient if needed often. This is still more obtuse than c++20's requires, but you don't have many options if your compiler does not support this.

With is_detected_v, all you will need is to define template type aliases of any expressions that you need to validate, and simply pass it in to the trait.

For example, the above solution can be solved succinctly as:

template <typename T>
using detect_initialize = decltype(std::declval<T&>().initialize());

...

if constexpr (is_detected_v<detect_initialize, decltype(item)>) {
...
}

Live Example

python how to check if tuple contains anything from list?

You could write a simple function:

def check_bad_words(words):
for word in words:
if word in BADWORD_triggers:
return True
return False

and then in your elif-statement:

elif check_bad_words(args):
pass

Detecting type inclusion in std::tuple at compile time

Here's another solution that is pretty similar to @HolyBlackCat's answer, but uses std::disjunction instead of a fold-expression, and can be used the same way you have in your question (it doesn't require ::value for the usage):

template<typename, typename>
struct tuple_holds;

template<typename ...Ts, typename T>
struct tuple_holds<std::tuple<Ts...>, T>
: std::disjunction<std::is_same<Ts, T>...> {};

Here's a demo.

How to extract all tuple elements of given type(s) into new tuple

Only C++17 is needed here.

std::tuple_cat is one of my favorite tools.

  1. Use a std::index_sequence to chew through the tuple

  2. Use a specialization to pick up either a std::tuple<> or a std::tuple<T> out of the original tuple, for each indexed element.

  3. Use std::tuple_cat to glue everything together.

  4. The only tricky part is checking if each tuple element is wanted. To do that, put all the wanted types into its own std::tuple, and use a helper class for that part, too.

#include <utility>
#include <tuple>
#include <iostream>

// Answer one simple question: here's a type, and a tuple. Tell me
// if the type is one of the tuples types. If so, I want it.

template<typename wanted_type, typename T> struct is_wanted_type;

template<typename wanted_type, typename ...Types>
struct is_wanted_type<wanted_type, std::tuple<Types...>> {

static constexpr bool wanted=(std::is_same_v<wanted_type, Types>
|| ...);
};

// Ok, the ith index in the tuple, here's its std::tuple_element type.
// And wanted_element_t is a tuple of all types we want to extract.
//
// Based on which way the wind blows we'll produce either a std::tuple<>
// or a std::tuple<tuple_element_t>.

template<size_t i, typename tuple_element_t,
typename wanted_element_t,
bool wanted=is_wanted_type<tuple_element_t, wanted_element_t>::wanted>
struct extract_type {

template<typename tuple_type>
static auto do_extract_type(const tuple_type &t)
{
return std::tuple<>{};
}
};

template<size_t i, typename tuple_element_t, typename wanted_element_t>
struct extract_type<i, tuple_element_t, wanted_element_t, true> {

template<typename tuple_type>
static auto do_extract_type(const tuple_type &t)
{
return std::tuple<tuple_element_t>{std::get<i>(t)};
}
};

// And now, a simple fold expression to pull out all wanted types
// and tuple-cat them together.

template<typename wanted_element_t, typename tuple_type, size_t ...i>
auto get_type_t(const tuple_type &t, std::index_sequence<i...>)
{
return std::tuple_cat( extract_type<i,
typename std::tuple_element<i, tuple_type>::type,
wanted_element_t>::do_extract_type(t)... );
}

template<typename ...wanted_element_t, typename ...types>
auto get_type(const std::tuple<types...> &t)
{
return get_type_t<std::tuple<wanted_element_t...>>(
t, std::make_index_sequence<sizeof...(types)>());
}

int main()
{
std::tuple<int, const char *, double> t{1, "alpha", 2.5};

std::tuple<double, int> u=get_type<int, double>(t);

std::cout << std::get<0>(u) << " " << std::get<1>(u) << std::endl;

std::tuple<int, int, int, char, char, char, double, double, float> tt;

auto uu=get_type<float, double>(tt);

static_assert(std::is_same_v<decltype(uu),
std::tuple<double, double, float>>);

return 0;
}


Related Topics



Leave a reply



Submit