How to express concepts over variadic template?
Asked Answered
B

2

7

I'd like to define a concept which just tuples with values of a specific type can satisfy.

Let's say for simplicity I just want to accept tuples just holding elements of a numeric type. How would I do this?

e.g.

std::tuple<int16_t, int32_t> // satisfies concept
std::tuple<std::string, double> // doesn't satisfy concept

The problem is I'd have to formulate something like "for_each_type". Also recursive concepts are not allowed.

Bitch answered 5/11, 2020 at 9:14 Comment(0)
U
11

Simply enough:

namespace impl {
    template <class T>
    struct is_tuple_of_integrals
    : std::false_type { };
    
    template <std::integral... Ts>
    struct is_tuple_of_integrals<std::tuple<Ts...>>
    : std::true_type { };
}

template <class T>
concept tuple_of_integrals = impl::is_tuple_of_integrals<T>::value;

I do wonder whether the intermediate trait can be omitted, but absent concept specializations I don't believe so.

Unto answered 5/11, 2020 at 9:22 Comment(5)
I heard you like concepts. So I put a concept in your concept, so you can check a constraint while checking a constraint :)Bise
@StoryTeller-UnslanderMonica it's concepts all the way down!Unto
I mean of course sfinae is an option (hence my upvote), but still I would be interested in a solution using only concepts. Or if that's not possible a reason why because there are very few questions about concepts at the moment on SO which makes it hard to learn for beginners.Bitch
@Bitch there's no SFINAE here, only a partial specialization. As noted, I believe we need one at some point to get to the tuple elements, and concepts cannot be partially specialized so we need something else in-between.Unto
@Bitch well, the first concept can only be called with the list of types directly. The second snippet defines a function template, not a concept -- although you could indeed use overloaded function templates inside decltype to perform the pattern-matching instead of a class template.Unto
M
9

My solution:

template<typename ... Args>
concept numeric_tuples = (std::is_integral_v<Args> && ...);

template<typename ... Args>
void foo(std::tuple<Args...> t) requires numeric_tuples<Args...> {

}

I used fold expression for the concept.

Mink answered 5/11, 2020 at 9:48 Comment(2)
Or a terser variant: template <std::integral... Ts> void foo(std::tuple<Ts...>) { }Unto
@Unto yes, your solution is even better.Mink

© 2022 - 2024 — McMap. All rights reserved.