Suppose that I have the following function:
template <typename Iterator>
void f()
{
std::list<int> numList;
Iterator it = numList.begin();
...
}
Iterator can be either std::list<int>::iterator or std::list<int>::const_iterator.
The above function compiles for std::list<int>::iterator, but for std::list<int>::const_iterator the list should be declared as const std::list<int>.
Is there a way to declare the type of the list either std::list<int> or const std::list<int> depending on whether Iterator is iterator or const_iterator?
It should be possible by using std::iterator_traits, <type_traits> and std::conditional, something similar to
using pointer_type = typename std::iterator_traits<Iterator>::pointer;
using list_type = typename std::conditional<std::is_const<pointer_type>::value, const std::list<int>, std::list<int>>::type;
list_type numList;
Mind this is untested so you should probably adjust it a little bit, it's just to give you the basic idea behind this. Please check this answer too.
Related
I am making a circular iterator class that behaves like a forward iterator, except it loops back to the beginning after reaching the end of a range.
template <typename T>
struct CircularIterator
{
CircularIterator(T* begin, T* end);
// Omitted overloaded operators
T* mBegin; // Points to beginning of range
T* mIter; // Current item
T* mEnd; // Points to end of range
};
There is no conversion from an STL iterator (e.g., std::vector<int>::iterator>) to a raw pointer (T*). The following code compiles with an error:
std::vector<int> vec{1, 2, 3};
CircularIterator<int> iter(vec.begin(), vec.end());
error: cannot convert β__gnu_cxx::__normal_iterator<int*, std::vector<int> >β to βint*β in initialization
How do I create a template class that can accept any type that satisfies std::forward_iterator<T> in the constructor? I would like to avoid creating a new template instance for each iterator type that is used (e.g., new CircularIterator for std::array<T>::iterator and std::deque<T>::iterator.)
Any advice would be appriciated. I'm definately at the far end of my template/concept knowledge and look forward to any resources to learn more. Thank you.
You can constrain the template parameter I of CircularIterator must satisfy std::forward_iterator, e.g.
#include <iterator>
template <std::forward_iterator I>
struct CircularIterator
{
CircularIterator() = default;
CircularIterator(I begin, I end);
// Omitted overloaded operators
I mBegin; // Points to beginning of range
I mIter; // Current item
I mEnd; // Points to end of range
};
Note that you need to provide a default constructor for CircularIterator because std::forward_iterator requires a default constructor.
Forward iterators don't have to be iterators to a contigous range so T* mBegin isn't suitable. You could instead store the iterators themselves. Here's one possible way using SFINAE with is_base_of_v and forward_iterator_tag:
#include <iterator>
#include <type_traits>
template <class It, class EndIt,
std::enable_if_t<std::is_base_of_v<
std::forward_iterator_tag,
typename std::iterator_traits<It>::iterator_category>,int> = 0>
struct CircularIterator {
CircularIterator(It begin, EndIt end)
: mBegin(begin), mIter(begin), mEnd(end) {}
It mBegin; // Points to beginning of range
It mIter; // Current item
EndIt mEnd; // Points to end of range
};
If you really want to store T* to get fewer instantiations of the class template, you would have to require the iterator to be a contiguous_iterator instead:
#include <concepts>
#include <iterator>
#include <type_traits>
template <class T>
struct CircularIterator {
CircularIterator(std::contiguous_iterator auto begin,
std::contiguous_iterator auto end)
: mBegin(begin != end ? &*begin : nullptr),
mIter(mBegin),
mEnd(std::next(mBegin, std::distance(begin, end))) {}
T* mBegin; // Points to beginning of range
T* mIter; // Current item
T* mEnd; // Points to end of range
};
// deduction guide:
template<class It, class EndIt>
CircularIterator(It, EndIt) ->
CircularIterator<typename std::iterator_traits<It>::value_type>;
... and used like in your example:
#include <vector>
int main() {
std::vector<int> vec{1, 2, 3};
// specifying `<int>` is optional with the added deduction guide:
CircularIterator iter(vec.begin(), vec.end());
}
Demo
Your desires are in direct competition
any type that satisfies std::forward_iterator in the constructor?
avoid creating a new template instance for each iterator type that is used
Pick one of those. There is no common type between std::vector<int>::iterator and std::deque<int>::iterator for you to have as the data members of CircularIterator<int>.
In a memory constrained environment, why are you even mixing std::array, std::vector and std::deque in the first place? Those are much larger templates. If the only container you use is std::vector, what does it matter whether you hold std::vector<int>::iterators or int * in CircularIterator<int>?
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.
Let's say that I have a C container (e.g., MyContainer) with contained objects stored as void* pointers. The only way to iterate through the elements of this container is via two interface functions:
getFirstElem(MyContainer const&, void*): Outputs the first element of the container.
getNextElem(MyContainer const&, void*): Outputs the next element of the container.
I want to code a generic function that iterates through the elements of this C container via the interface functions mentioned above and copy their values into a C++ container (e.g. std::vector).
What I've done so far:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
typename std::iterator_traits<OutputIterator>::value_type elem;
if(getFirstElem(cont, &elem)) {
do {
*first = elem;
++first;
} while(getNextElem(cont, &elem))
}
}
The above example works OK with normal iterators. However, it fails to compile with output iterators (e.g., copy_container(cont, std::back_inserter(myvector));).
The reason is that std::iterator_traits::value_type results in void in cases where the argument type is an output iterator.
Is there a way to make this generic function work for output iterators as well?
I know that in C++11 it could be done by using decltype (e.g., decltype(*first)), but I'm particularly interested in pre-C++11 solutions since I use an old C++ compiler (gcc v4.4.7).
As correctly observed, the value_type of an output iterator is void. So there not much to do apart from replacing this :
typename std::iterator_traits<OutputIterator>::value_type elem;
with this
decltype(*first) elem;
(even though the Standard doesn't guarantee it'll work - a proxy might be returned by dereferencing an output iterator).
As you said no C++11 solution so a redesign might be needed. Here are some options:
1. Pass the container
Instead of an iterator to the first element, you could pass a reference to the container. It seems like all you want is a push_back.
template<template<typename,typename> class stlContainer>
void copy_container(
MyMontainer const &cont, OutputIterator first)
{
// insertion in stlContainer
then all you need is a layer of traits to dispatch to the right implementation of insertion per container
2. Pass an extra template parameter
The value type could be an extra template parameter.
template<typename value_type, typename OutputIterator>
void copy_container(MyMontainer const &cont, OutputIterator first)
{
value_type elem;
...
You may use typetraits and specialization
template <typename IT>
struct it_value_type
{
typedef typename std::iterator_traits<IT>::value_type elem;
};
template <typename Container>
struct it_value_type<std::back_insert_iterator<Container>>
{
typedef typename Container::value_type elem;
};
template <typename Container>
struct it_value_type<std::front_insert_iterator<Container>>
{
typedef typename Container::value_type elem;
};
And then you code becomes:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
typename it_value_type<OutputIterator>::elem elem;
if (getFirstElem(cont, &elem)) {
do {
*first = elem;
++first;
} while (getNextElem(cont, &elem));
}
}
There are different ways to solve this, I did it like this:
template <class T>
std::enable_if_t<!std::is_same_v<typename T::container_type::value_type, void>, size_t> read(T first, size_t count)
{
typedef typename T::container_type::value_type value_type;
I have another one for the usual iterator.
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());
}
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;
}