Search code examples
c++tuplesc++14type-traits

How to static assert whether all types of a tuple fulfill some condition?


I have some type traits SomeTraits from which I can extract whether a type T fulfills some condition, through SomeTraits<T>::value. How would one go over all the types of a given std::tuple<> and check (through say a static assert) whether they all fulfill the above condition? e.g.

using MyTypes = std::tuple<T1, T2, T3>;
// Need some way to do something like
static_assert(SomeTupleTraits<MyTypes>::value, "MyTypes must be a tuple that blabla...");

where SomeTupleTraits would check whether SomeTraits<T>::value == true for each type inside MyTypes?

I am restricted to C++14.


Solution

  • As a one liner (newlines optional), you can do something like:

    // (c++20)
    static_assert([]<typename... T>(std::type_identity<std::tuple<T...>>) {
        return (SomeTrait<T>::value && ...);
    }(std::type_identity<MyTypes>{}));
    

    Or you can create a helper trait to do it:

    // (c++17)
    template<template<typename, typename...> class Trait, typename Tuple>
    struct all_of;
    
    template<template<typename, typename...> class Trait, typename... Types>
    struct all_of<Trait, std::tuple<Types...>> : std::conjunction<Trait<Types>...> {};
    
    static_assert(all_of<SomeTrait, MyTypes>::value);
    

    Or in C++11, you can reimplement std::conjunction inside the helper trait:

    template<template<typename, typename...> class Trait, typename Tuple>
    struct all_of;
    
    template<template<typename, typename...> class Trait>
    struct all_of<Trait, std::tuple<>> : std::true_type {};
    
    template<template<typename, typename...> class Trait, typename First, typename... Rest>
    struct all_of<Trait, std::tuple<First, Rest...>> :
        std::conditional<bool(Trait<First>::value),
                         all_of<Trait, std::tuple<Rest...>>,
                         std::false_type>::type::type {};
    
    static_assert(all_of<SomeTrait, MyTypes>::value, "");