Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 366
Kelemen Máté Avatar asked May 14 '20 09:05

Kelemen Máté


People also ask

What is the iterator concept?

In computer programming, an iterator is an object that enables a programmer to traverse a container, particularly lists. Various types of iterators are often provided via a container's interface.

How are C++ iterators implemented?

An iterator is an object that points to an element inside a container. Like a pointer, an iterator can be used to access the element it points to and can be moved through the content of the container. Each container in the C++ Standard Library provides its own iterator, as well as some methods to retrieve it.

What are the types of iterator in C++?

There are various kinds of iterators: input, output, forward, bidirectional, and random-access.


3 Answers

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)
{
    // ...
}
like image 108
L. F. Avatar answered Oct 22 '22 12:10

L. F.


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

like image 6
StoryTeller - Unslander Monica Avatar answered Oct 22 '22 13:10

StoryTeller - Unslander Monica


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:

  • https://en.cppreference.com/w/cpp/language/constraints and
  • https://en.cppreference.com/w/cpp/concepts

Godbolt example

like image 5
Mika Fischer Avatar answered Oct 22 '22 12:10

Mika Fischer