c++ iterator of any container with specific value type using concepts
Asked Answered
J

3

14

I want to get rid of all the unholy enable_ifs in my templates and replace them with C++20 concepts, however there's barely any info on concepts and the syntax changes with just about any source I read.

Here's a function that takes two iterators of any container with MyClass values:

template <class IteratorType, typename = std::enable_if<std::is_same<
                                typename std::iterator_traits<IteratorType>::value_type,
                                MyClass
                            >::value, void>>
void myFunction( IteratorType begin, IteratorType end ) {}

I know this function could be converted using concepts but I just can't find good leads to start with.

Juncaceous answered 14/5, 2020 at 9:19 Comment(0)
P
6

Probably not the easiest to understand reference, but the normative source of information for concepts is the available standard draft. Where a concept definition is specified grammatically as

1 A concept is a template that defines constraints on its template arguments.

concept-definition:
  concept concept-name = constraint-expression ;
concept-name:
  identifier

It's pretty much just like a bool variable template constant, but it's defined with the concept keyword. So to translate your condition directly to a concept is essentially this

template<typename T>
concept MyClassIter = std::is_same_v<
                        MyClass, 
                        typename std::iterator_traits<T>::value_type
                      >;

With the concept in hand, we can use it as a type constraint on a template's type parameter, thus transforming your template into this

template <MyClassIter IteratorType>
void myFunction( IteratorType begin, IteratorType end ) {}

If the constraint is not satisfied for a type, this overload is discarded. Not satisfied in this context also includes substitution failures. So it's the same condition you had originally.

Live example

Pulchritude answered 14/5, 2020 at 10:1 Comment(1)
Better to use std::same_as in case other constraints might one day be involved.Arellano
R
6

To fit in with the C++20 Ranges ecosystem:

template <std::input_iterator I, std::sentinel_for<I> S>
    requires std::same_as<std::iter_value_t<I>, MyClass>
constexpr void myFunction(I begin, S end)
{
    // ...
}
Roble answered 14/5, 2020 at 10:26 Comment(0)
T
5

The most straightforward translation would be

template <typename IteratorType>
requires std::same_as<typename std::iterator_traits<IteratorType>::value_type, MyClass>
void myFunction(IteratorType begin, IteratorType end) {}

See:

Godbolt example

Tepic answered 14/5, 2020 at 10:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.