Search code examples
c++c++-concepts

How to declare a template function that takes an output_iterator of T?


I want to put objects into a container (which container is not fixed).

For that I want to use the concept std::output_iterator.

How would I define a function that takes for example a std::insert_iterator<std::vector<T>> and a std::insert_iterator<std::list<T>>?

the concept std::output_iterator takes two template arguments : I and T. So i am unsure how I would declare such a function.

I could do it like oldschool <algorithm> and declare it like this:

template<typename OutIter>
void foo(OutIter writer);

but thats not that expressive imo.


UPDATE: Here is my attempt based in @RemyLebeau's answer:

#include <iterator>
#include <vector>
template<typename I, typename T, std::output_iterator<I,T> OutIter>
void foo(OutIter writer) {
    writer++ = T();
}

int main() {

    std::vector<int> ints;
    auto inserter = std::insert_iterator(ints,ints.end());
    foo(inserter);
}

https://godbolt.org/z/afe9rz3c4


Solution

  • @Remy Lebeau has the right idea, but not the right execution. The first template argument to a concept is the type being constrained and does not have to be specified when used to restrain another template arg.

    Their answer with correct code:

    #include <iterator>
    #include <vector>
    
    template<typename T, std::output_iterator<T> OutIter> // note: no template argument I required
    void foo(OutIter writer) {
        writer++ = T();
    }
    
    int main() {
    
        std::vector<int> ints;
        auto inserter = std::insert_iterator(ints,ints.end());
        foo<int>(inserter); // note you have to specify int when calling foo
        return 0;
    }
    

    This is not entirely your use-case, since you don't want to specify the type for foo's iterator when calling the function. But using the output_iterator concept, foo can specify the iterator type itself:

    #include <iterator>
    #include <vector>
    
    template<std::output_iterator<int> OutIter> // Explicitly requests an iterator that ints can be written to
    void foo(OutIter writer) {
        writer++ = int{};
    }
    
    int main() {
    
        std::vector<int> ints;
        auto inserter = std::insert_iterator(ints,ints.end());
        foo(inserter);
        return 0;
    }