Search code examples
c++templatesc++-conceptsc++23

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?


Solution

  • 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