Raildex
Raildex

Reputation: 4765

How to constrain the value type of std::input_iterator?

I have the following code at the moment:

#include <iterator>
#include <vector>
struct bar{};
struct details {};
struct foo {
    details det;
    std::vector<bar> data;
};

template <std::input_iterator Iter>
foo create_foo(const details& details, Iter begin, Iter end) {
    return foo {
        .det = details,
        .data = {begin, end}
    };
}

int main() {

    std::vector<bar> bars = {bar{},bar{},bar{}};
    create_foo({}, bars.begin(), bars.end());
    return 0;
}

Godbolt demo

foo::data is a Container for bars. It's constructor takes two Iterators.

I want to constrain the input iterators to be iterators of containers containing bar only, e.g. a std::vector<bar>::iterator or a std::list<bar>::iterator

How would I achieve this with concepts?

Upvotes: 2

Views: 112

Answers (2)

Oersted
Oersted

Reputation: 2734

you can combine two concepts: std::input_iterator and its value_type being bar:

template <typename T>
concept input_iterator_bar =
    std::input_iterator<T> && std::same_as<bar, typename T::value_type>;

And use it with create_foo:

template <input_iterator_bar  Iter>
foo create_foo(const details& details, Iter begin, Iter end) {
...

LIVE


As stated in https://stackoverflow.com/a/79438946/21691539, here is a version applicable in more situations.

template <typename T>
concept input_iterator_bar =
    std::input_iterator<T> && std::same_as<bar, std::iter_value_t<T>>;

Upvotes: 3

wohlstad
wohlstad

Reputation: 29009

You can add a requires clause to create_foo:

template <std::input_iterator Iter>
foo create_foo(const details& details, Iter begin, Iter end) 
              requires std::is_same_v<typename Iter::value_type, bar> 
{
   // ...
}

Live demo 1


As @StoryTeller-UnslanderMonica commented, using std::same_as and std::iter_value_t for the requires clause will improve it and support pointers and a wider range of containers:

template <std::input_iterator Iter>
foo create_foo(const details& details, Iter begin, Iter end) 
              requires std::same_as<std::iter_value_t<Iter>, bar>
{
   // ...
}

Live demo 2

Upvotes: 6

Related Questions