"Generic" iterator in c++ - c++

I have:
void add_all_msgs(std::deque<Message>::iterator &iter);
How can I make that function "generic", so it can take any kind of inputiterators ? I don't really care if it's iterating a deque,a vector or something else, as long as the iterator is iterating Message's. - is this at all straight forward possible in c++ ?

template <typename Iterator>
void add_all_messages(Iterator first, Iterator last)
usage :
vector<message> v;
add_all_messages(v.begin(), v.end());
You need to specify the end, otherwise you won't know when to stop! It also gives you the flexibility of adding only a subrange of a container.

template<class InputIterator>
void add_all_msgs(InputIterator iter);
Usage:
std::deque<Message> deq;
add_all_msgs(deq.begin());

If you want the compiler to check whether the iterator actually refers to Message objects, you can use a technique like the following.
template <typename InputIterator, typename ValueType>
struct AddAllMessages { };
template <typename InputIterator>
struct AddAllMessages<InputIterator, Message> {
static void execute(const InputIterator &it) {
// ...
}
};
template <typename InputIterator>
void add_all_msgs(const InputIterator &it) {
AddAllMessages<InputIterator,
typename std::iterator_traits<InputIterator>::value_type>::execute(it);
}

If you don't want to templatize your add_all_msgs function, you can use adobe::any_iterator:
typedef adobe::any_iterator<Message, std::input_iterator_tag> any_message_iterator;
void add_all_msgs(any_message_iterator begin, any_message_iterator end);

It's difficult to have dynamic polymorphism with C++-style iterators. operator++(int) returns by value, which afaik is intractable: you can't have a virtual member function which returns *this by value without it being sliced.
If possible, I recommend using templates as everyone else says.
However if you do need dynamic polymorphism, for example because you can't expose the implementation of add_all_msgs as a template would do, then I think you could pretend to be Java, like this:
struct MessageIterator {
virtual Message &get() = 0;
virtual void next() = 0;
// add more functions if you need more than a Forward Iterator.
virtual ~MessageIterator() { }; // Not currently needed, but best be safe
};
// implementation elsewhere. Uses get() and next() instead of * and ++
void add_all_msgs(MessageIterator &it);
template <typename T>
struct Adaptor : public MessageIterator {
typename T::iterator wrapped;
Adaptor(typename T::iterator w) : wrapped(w) { }
virtual Message &get() {
return *wrapped;
}
virtual void next() {
++wrapped;
}
};
int main() {
std::deque<Message> v;
Adaptor<std::deque<Message> > a(v.begin());
add_all_msgs(a);
}
I've checked that this compiles, but I haven't tested it and I've never used this design before. I also haven't bothered with const-ness - in practice you probably want a const Message &get() const. And at the moment the adaptor has no way of knowing when to stop, but then neither does the code you started with, so I've ignored that too. Basically you'd need a hasNext function which compares wrapped against an end iterator supplied to the constructor.
You might be able to do something with a template function and const references, so that the client doesn't have to know about or declare that nasty Adaptor type.
[Edit: come to think of it, it's probably better to have a stub add_all_msgs function template, that wraps its parameter in an Adaptor and then calls real_add_all_msgs. This completely hides the adaptor from the client.]

Slightly simpler that the above (in that it leverages existing libraries):
#include <boost/static_assert.hpp> // or use C++0x static_assert
#include <boost/type_traits/is_same.hpp>
template <typename InputIterator>
void add_all_msgs( InputIterator it ) {
BOOST_STATIC_ASSERT(( boost::is_same<
typename std::iterator_traits<InputIterator>::value_type,
Message>::value ));
// ...

#include <deque>
#include <vector>
#include <list>
#include <string>
using namespace std;
template<typename T>
void add_all_msgs(T &iter)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
std::deque<string>::iterator it1;
std::vector<string>::iterator it2;
std::list<string>::iterator it3;
add_all_msgs(it1);
add_all_msgs(it2);
add_all_msgs(it3);
return 0;
}

Related

std::array::iterator that ignores the size template

I am implementing a function that wants to loop over a number of elements in an std::array, but I don't really care how long the std::array is. So I was thinking of the following function:
#include <stdio.h>
#include <array>
#include <iterator>
void foo(std::array<bool,0>::const_iterator begin, std::array<bool,0>::const_iterator end)
{
printf("iterator");
}
int main()
{
std::array<bool, 25> one;
std::array<bool, 33> two;
foo(one.cbegin(), one.cend());
foo(two.cbegin(), two.cend());
}
I am quite okay with this, except for the std::array<bool,0>. My question is, is there another way to specify the iterator that is required for this function?
Update
There are some things I should mention. Of course this code is part of a bigger scope and I tried to hide as much detail as I could.
I want to ensure that the iterator being used is of bools.
I am using C++14
The function is part of a class interface and I want to be able to handle multiple array sizes. I don't want to bother the implementors of the interface to know exactly what the size of the array is.
class MyInterface
{
public:
virtual foo(std::array<bool,0>::const_iterator begin, std::array<bool,0>::const_iterator end) = 0;
~MyInterface() = default;
};
I remembered that virtual functions cannot be templated. That means I would have to template my whole interface and that would exactly loose the point of why I was trying this in the first place.
You can just make it a function template as
template <typename I>
void foo(I begin, I end)
{
std::cout << "iterator";
}
You don't need to care about container type (and the size), you can pass iterators of std::array, std::vector and std::string and so on, even raw pointers (which also satisfies iterator's requirements).
Just use span:
#include <array>
#include <span>
class MyInterface {
public:
virtual void foo(std::span<bool> barr) = 0;
// interface destructors should be virtual
virtual ~MyInterface() = default;
};
void bar(MyInterface& interface) {
std::array<bool, 42> arr;
interface.foo(arr);
}
If you don't have access to a C++20 compiler, you may use gsl::span from gsl instead.
Use a template:
template <size_t N>
void foo(std::array<bool,N>::const_iterator begin, std::array<bool,N>::const_iterator end)
{
printf("iterator");
}
And now as long as both iterators come from an array of size N this function will work.
If you want to accept iterators from different sized arrays, you just need to add another template parameter for the second iterator like
template <size_t N, size_t M>
void foo(std::array<bool,N>::const_iterator begin, std::array<bool,M>::const_iterator end)
{
printf("iterator");
}
If the function accepts two iterators when the referring std::array is redundant. Just declare the function like
template <class Iterator>
void foo( Iterator first, Iterator last );
In the declaration you can name the iterator that corresponds to the used iterator type in the function like for example
template <class ForwardIterator>
void foo( ForwardIterator first, ForwardIterator last );
Or instead of the name ForwardIterator you could use the name BidirectionalIterator or RandomAccessIterator for self-documenting.
If you need to know the value type of the iterator you can use different approaches. For example
template <class Iterator>
void foo( Iterator first, Iterator last )
{
using value_type = typename std::iterator_traits<Iterator>::value_type;
if ( first != last )
{
value_type item1 = *first;
// or
auto item2 = *first;
//
const auto &item3 = *first;
//...
}
}
In this case you will have a flexible function definition. For example if in future you will change std::array<N, bool> to std::vector<bool> the function will as usual work.

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());
}
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.
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
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.

Non-template function that processes any container of elements of specific type

I'd like to have a function as described in title.
I've noticed that STL algorithms that work with containers of any type (list, vector, etc) containing elements of any type (int, double) provide genericity by using iterator types as template parameters, e.g.
template<typename _II, typename _OI>
inline _OI
copy(_II __first, _II __last, _OI __result)
This is a good method until the algorithm works for any type of elements. The only requirement for element type is that it must have copy constructor.
But suppose we have one concrete type
class MyElement
{
public:
void doSomethingWithElement();
};
and we want to implement a function that processes number of elements of this type by calling function doSomethingWithElement().
Writing a function that receives container of specific type is not very convenient because many containers are treated in the same way (e.g. iterators), and if there will be need for processing containers of different types we'll be forced to duplicate the code. Writing a template works fine, but it seems ugly because we have to implement function in place where it is declared (in header file). Also, when we want to process elements of only one type, parametrizing this type is not the right way to achieve the goal.
I've been thinking about iterator interface that could be used like
void processContainer(IIterator<MyElement> begin, IIterator<MyElement> end);
If this iterator had pure virtual operator++ and operator* that were implemented in derived classes, we could pass such objects to processContainer. But there is a problem: if IIterator is abstract class, we can't instantiate it in the implementation of processContainer, and if we pass a pointer to IIterator, this function will be able to modify it.
Does anybody know any other hack to do this? Or would be another approach better than these ones above? Thanks in advance.
The simpler approach is to ignore the restriction and just implement your function as a template for any iterator. If the iterator does not refer to the type, then the user will get a horrible error message in the lines of "type X does not have doSomethingWithElement member function`.
The next thing would be to provide a static_assert, the function would still take any iterator (meaning that it will participate in overload resolution for any type) but the error message will be slightly more informative.
Furthermore you can decide to use SFINAE to remove the overload from the set of candidates. But while SFINAE is a beautiful golden hammer, I am not sure that you have the appropriate nail at hand.
If you really want to go further down the lane, you can take a look at any_iterator in the Adobe libraries as an example on how to perform type erasure on the iterator type to avoid the template. The complexity of this approach is orders of magnitude higher than any of the previous, and the runtime cost will also be higher, providing the only advantage of a cleaner ABI and less code size (different iterators can be passed to a single function).
You could use std::for_each(): http://www.cplusplus.com/reference/algorithm/for_each/
full code:
void callDoSomething(MyElement &elem)
{
elem.doSomething();
}
int main()
{
std::vector<MyElement> vec(100);
std::for_each(vec.begin(), vec.end(), callDoSomething);
}
You can't do exactly what you want to do. You could use enable_if to limit the function's availability:
template < typename Container >
typename enable_if<is_same<typename Container::value_type, MyElement>,void>::type processContainer(Container c)...
It's not possible to create an abstract iterator that has the full iterator functionality - including the ability to make copies of itself - without changing the iterator interface. However, you can implement a subset of iterator functionality using an abstract base class:
#include <iterator>
#include <vector>
#include <list>
template<typename T>
struct AbstractIterator
{
virtual bool operator!=(const AbstractIterator<T>& other) const = 0;
virtual void operator++() = 0;
virtual T& operator*() = 0;
};
template<typename Iterator>
struct ConcreteIterator : AbstractIterator<typename std::iterator_traits<Iterator>::value_type>
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
Iterator i;
ConcreteIterator(Iterator i) : i(i)
{
}
virtual bool operator!=(const AbstractIterator<value_type>& other) const
{
return i != static_cast<const ConcreteIterator*>(&other)->i;
}
virtual void operator++()
{
++i;
}
virtual value_type& operator*()
{
return *i;
}
};
template<typename Iterator>
ConcreteIterator<Iterator> wrapIterator(Iterator i)
{
return ConcreteIterator<Iterator>(i);
}
class MyElement
{
public:
void doSomethingWithElement();
};
void processContainerImpl(AbstractIterator<MyElement>& first, AbstractIterator<MyElement>& last)
{
for(; first != last; ++first)
{
(*first).doSomethingWithElement();
}
}
template<typename Iterator>
void processContainer(Iterator first, Iterator last)
{
ConcreteIterator<Iterator> wrapFirst = wrapIterator(first);
ConcreteIterator<Iterator> wrapLast = wrapIterator(last);
return processContainerImpl(wrapFirst, wrapLast);
}
int main()
{
std::vector<MyElement> v;
processContainer(v.begin(), v.end());
std::list<MyElement> l;
processContainer(l.begin(), l.end());
}

Iterators and STL containers

I need to make some specific constructor which gets two iterators: start iterator and end iterator.
I have some code and its works:
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
class A
{
public:
T a[10];
typename std::vector<T>::iterator itStart, itEnd;
A(typename vector<T>::iterator itStart, typename vector<T>::iterator itEnd):itStart(itStart),itEnd(itEnd){}
void see()
{
int i=0;
while(itStart != itEnd)
{
cout<<*itStart<<endl;
a[i] = *itStart;
itStart++;
i++;
}
}
};
template <typename Iterator>
double Sum( Iterator begin, Iterator end );
int main()
{
cout << "Hello world!" << endl;
vector<int> v;
v.push_back(1);
v.push_back(1);
v.push_back(2);
v.push_back(3);
class A<int> a(v.begin(),v.end());
a.see();
return 0;
}
But I want to make constructor arguments work with all STL containers(like Set,List,Map etc.) and with normal arrays(normal pointers).
So can I make it in generic template way? Something like that:
template<typename T>
class A
{
public:
iterator<T> itStart, itEnd;
A(iterator<T> itStart, iterator<T> itEnd):itStart(itStart),itEnd(itEnd){}
void see()
{
while(itStart != itEnd)
{
cout<<*itStart<<endl;
itStart++;
}
}
};
I know code the above is wrong but I want to explain my idea.
Of course I can overload constructor but I am too lazy to that. Too many STL containers.
Is some template way to solve that issue?
Obviously you need to make the iterator type a template argument to your class
template<class T, class Iter>
class A
{
Iter first, last;
A(Iter first, iter last):first(first), last(last){}
};
But now it becomes uncomfortable to explicitly specify the template argument
A<int, vector<int>::iterator > a;
To avoid that, simply create a factory function
template<class T, class Iter>
A<T, Iter> make_A(Iter first, iter last)
{
return A<T, Iter>(first, last);
}
Now, instead of directly creating an object of A, you can use the function
auto my_A = make_A<int>(v.begin(), v.end());
Looking at one of STL's things such as std::fill:
template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );
we can be inspired:
template<typename ITR, typename T>
class A
{
A(ITR itStart, ITR itEnd):itStart(itStart),itEnd(itEnd){}
...
Perhaps you could make use of the notion of an input sequence (iseq).
An input sequence is denoted by a pair of iterators (begin and end).
Of course, you would need to create overloads of all the STL algorithms that accept an iseq instead of a pair of iterators.
Then your example could just use for_each (overloaded to accept an iseq).
Example code can be found in TC++PL 3rd edition (Stroustrup) section 18.3.1.

How to handle any iterator without putting the code in the header file?

Here is the problem:
Header file (part of a library's API):
template <typename IterType>
void foo(const IterType &begin, const IterType &end);
CPP file:
template <typename IterType>
void my_really_large_implementation_specific_function(const IterType &begin, const IterType &end) {
// ...
}
Is is possible to make foo() call my_really_large_implementation_specific_function() without including my_really_large_implementation_specific_function()'s code in a header file and without making more than one instance of its template? Maybe using some kind of wrapper iterator class, but I'm not sure how.
Look here for an exemple using any_iterator that is included in Boost.Range : http://geek-cpp.blogspot.fr/2012/11/using-boost-anyiterator-to-hide.html
#include <string>
// note that there is no include to multi_index here!
#include <boost/scoped_ptr.hpp>
#include <boost/range/concepts.hpp>
#include <boost/range/detail/any_iterator.hpp>
class hidden_container; //forward declare the hidden container
class exemple {
public:
boost::scoped_ptr<hidden_container> impl; //hidden container behind pointer
// declare a type erased iterator that can iterate over any container of std::string
// this could be a std::vector<std::string>::const_iterator or a std::list<std::string>::const_iterator
typedef boost::range_detail::any_iterator<
const std::string,
boost::forward_traversal_tag,
const std::string&,
std::ptrdiff_t
> const_iterator;
//ctor
exemple();
// abstracted iterators
const_iterator begin() const;
const_iterator end() const;
};
Have you had a look at boost::any_range? It uses type erasure to hide template types with virtual method calls as a trade-off.
If you want your function to be able to operate on arbitrary iterator types then the body needs to appear in the header.
If you need to support only one iterator type then it doesn't need to be a template and can appear in the source file.
Maybe you simply want to do a for_each?
// In the header:
void my_really_large_implementation_specific_function(const common_base_class& c);
template <typename IterType>
void foo(const IterType &begin, const IterType &end)
{
std::for_each(begin, end, my_really_large_implementation_specific_function);
}