Matthias
Matthias

Reputation: 10369

Is there a "generic" iterator type to be used in C++ for function parameters?

I have a C++ class that contains a std::list as member. Now I want to add a method that can be used to insert values of another container into that list. Something like this:

template<class factType>
class BeliefSet
{
    std::list<factType> m_List;
    void SetFacts(??? IterBegin, ??? IterEnd)
    {
        m_List.insert(m_List.end(), IterBegin, IterEnd);
    }
};

Now my question is: What do I have to replace ??? with, so that it can take the iterator of any (or at least most common) std containers, like list, vector, etc.? I tried it with std::iterator<std::input_iterator_tag, factType>, but that didn't seem to work.

Note that this should also work with a copy constructor, like this:

const std::list<factType>& GetFacts() const
{
    return m_List;
}

// Copy constructor.
explicit BeliefSet(const BeliefSet& Other)
{
    auto facts = Other.GetFacts();
    SetFacts(facts.begin(), facts.end());
}

Upvotes: 7

Views: 3177

Answers (3)

You need to make SetFacts be a template. Normally this would be a disadvantage, because it means the method has to be inline. However, as BeliefSet is already a class template, that isn't a problem.

template<class factType>
class BeliefSet
{
    std::list<factType> m_List;

    template <class It>
    void SetFacts(It IterBegin, It IterEnd)
    {
        m_List.insert(m_List.end(), IterBegin, IterEnd);
    }
};

If you call SetFacts with something that isn't an iterator, you'll get error messages out of list::insert. If you are really lucky, you may be able to understand them!

Note that I pass the iterators by value (rather than const reference) - that is because one normally expects iterators to be cheap to copy.

Upvotes: 6

Pete Becker
Pete Becker

Reputation: 76245

template <class Iter>
void SetFacts(Iter first, Iter last)
    {
        m_List.insert(m_List.end(), first, last);
    }

I also changed the names of the arguments to the usual idiom.

Upvotes: 2

Arunmu
Arunmu

Reputation: 6901

Use iterator_tag.

template<class factType>
class BeliefSet
{

    std::list<factType> m_List;
    template <typename Iter>
    void SetFacts(Iter IterBegin, Iter IterEnd)
    {
        SetFacts_Impl(IterBegin, IterEnd, 
         typename std::iterator_traits<Iter>::iterator_category());
    }
private:
    template <typename Iter>
    void SetFacts_Impl(Iter IterBegin, Iter IterEnd, std:: bidirectional_iterator_tag )
    {
        std::copy( IterBegin, IterEnd, std::back_inserter( m_List ) );
    }
};

This makes sure that it will take any iterator that atleast follows the requirements set by bidirectional iterator. So will cover both list and vector

Upvotes: 2

Related Questions