how to define in C++20 a concept to check if a type matches any of the types in a type-list
M

1

9

I want to define a concept in C++ (<= C++20) to check if a type matches any of the types define in a type-list struct.

The following is my attempt so far:

template<typename... Types>
struct TypeList {};

using SupportedTypes = TypeList<int, bool, float, long>;
    
template<typename T, typename... Types>
concept IsAnyOf = (std::is_same_v<T, Types> || ...);
    
static_assert(IsAnyOf<bool, SupportedTypes>);

I have also tried using:

template<typename T, typename... Types>
concept IsAnyOf = std::disjunction_v<std::is_same<T, Types>...>;

But my static assertion fails:

Static assertion failed
because 'IsSupportedType<_Bool, SupportedTypes>' evaluated to false
because 'std::is_same_v<_Bool, meta::TypeList<int, _Bool, float, long> >' evaluated to false

I understand it probably has to do with the fact that I'm passing SupportedTypes to the concept without properly unpacking the types inside it, and hence in the static assertion I'm checking if bool is the same as SupportedTypes, as opposed to checking if bool is the same as any of the types inside SupportedTypes; but I can't get it to work nonetheless.

Metencephalon answered 12/3 at 9:38 Comment(2)
Thank you @Alan. Just for me to learn, how should I show research effort next time? I can assure you there has been... I'm just not versed with metaprogramming and argument unpacking syntaxMetencephalon
@Alan what? The question has a clear objective, shows their initial attempt, and explains what they are stuck on.Megdal
L
9

how to define in C++20 a concept to check if a type matches any of the types in a type-list

Method 1

You can change the program to as shown below. This is more readable than method 2.

template<typename... Types>
struct TypeList {};

template <typename T, typename List>
concept IsAnyOf = []<typename... Types>(TypeList<Types...>) 
{
   return (std::is_same_v<Types, T> || ...);
}(List());

Working demo


This is how you would use it:

using SupportedTypes = TypeList<double, float, std::string, bool>;

int main() 
{
    std::cout << IsAnyOf<bool, SupportedTypes>; //true
    std::cout << IsAnyOf<char, SupportedTypes>; //false
}

Method 2

Note there are also other ways to do this like using std::tuple and std::inxex_sequence as shown in this alternative.

template <typename T, typename Typelist>
concept is_any_of = []<std::size_t... Indices>(std::index_sequence<Indices...>) 
{
   return (std::is_same_v<std::tuple_element_t<Indices, Typelist>, T> || ...);
}(std::make_index_sequence<std::tuple_size_v<Typelist>>());

Lymphoblast answered 12/3 at 9:50 Comment(7)
That works like a charm. Thank you! It reads as black magic to me for now, but I'll do some reading. Any resource you would recommend to get some better understanding behind template metaprogramming or C++ concepts?Metencephalon
You don't need to use std::tuple here, you can pass OP's TypeList with []<typename... Types>(TypeList<Types...>) insteadMegdal
@Metencephalon I learnt all this from the books here. You're welcome.Lymphoblast
How do you mean @Caleth?Metencephalon
godbolt.org/z/9xr4PWT8s It's the same basic idea, but shorterMegdal
@Megdal Updated. Now added as mentioned 1 and 2 and explicitly added that method 1(that doesn't use tuple etc) is more readable in this case.Lymphoblast
@monre: Maybe the lambda expression in the concepts body is throwing you off ? Lambdas can be templates, too (and even variadic at that). It certainly adds to the special character density in the snippet.. ;)Hoyle

© 2022 - 2024 — McMap. All rights reserved.