3

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.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
zhanginou
  • 177
  • 6

1 Answers1

6

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, "");
Artyer
  • 31,034
  • 3
  • 47
  • 75
  • Unfortunately it seems `std::conjunction` is a C++17 feature (and `std::type_identity` C++20). I am restricted to C++14. Is there another C++14 compatible method that could work with a helper trait? Or is the most straightforward method simply to reimplement `std::conjunction`? – zhanginou May 18 '22 at 18:07
  • 1
    @zhanginou Reimplementing `std::conjunction` is pretty easy to do in C++14, but you can do it directly as I've edited my answer to do so – Artyer May 18 '22 at 18:14
  • Thanks! And how would one modify the above if the Trait uses SFINAE as the second template argument, e.g. `template struct SomeTrait : std::false_type { }; template struct SomeTrait::value> : std::true_type { }`? With the above method, the compiler complains that `type/value mismatch at argument 1 in template parameter list for 'template – zhanginou May 18 '22 at 19:52
  • 1
    This is [CWG150](https://wg21.link/CWG150) (See this question: https://stackoverflow.com/q/48645226). I've added an extra `typename...` parameter pack to the template template argument so it should work even in C++11 – Artyer May 18 '22 at 19:58