Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

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());
}
like image 717
Matthias Avatar asked Dec 09 '16 15:12

Matthias


2 Answers

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.

like image 184
Martin Bonner supports Monica Avatar answered Oct 05 '22 02:10

Martin Bonner supports Monica


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

like image 36
Arunmu Avatar answered Oct 05 '22 01:10

Arunmu