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.
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>?
Consider a function that accepts one or more parameters (e.g. file names). In order to make it versatile, it is advantageous to write it for a general iterator range:
template<class Iter>
void function(Iter first, Iter last)
{
// do something
}
Now we can invoke it in the following way, independently of how we store the arguments:
WhateverContainer container;
function(std::begin(container), std::end(container));
For example, the STL relies heavily on this paradigm.
Now, imagine we want to invoke the function with a single argument that is not stored in a container. Of course we can write:
const int value = 5;
std::vector<int> vec(1, value);
function(std::begin(vec), std::end(vec));
But this solution seems clumsy and wasteful to me.
Question: Is there a better low-overhead way of creating an iterator-range-compatible representation of a single variable?
You can use pointers, for once:
function(&value, &value + 1);
In generic code, std::addressof instead of the unary operator & is somewhat safer, depending on your level of paranoia.
You can of course wrap this in an overload for easier use:
template <class T>
decltype(auto) function (T &&e) {
auto p = std::addressof(e);
return function(p, p + 1);
}
You can treat it like an array of one element per [expr.unary.op]/3:
function(&value, &value + 1);
For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), an object that is not an array element whose address is taken in this way is considered to belong to an array with one element of type T.
You can also overload your function template function for a single-element range:
template<typename Iter>
void function(Iter first) {
return function(first, std::next(first)); // calls your original function
}
This way, your original function function remains compatible with iterator ranges. Note, however, that using this overload with an empty range will result in undefined behavior.
For a single element, value, you can use the overload above:
function(&value); // calls overload
Since operator & may be overloaded, consider also using std::addressof instead of &, as already mentioned in this answer.
For a range consisting of a single element, you can use the overload above as well, which only needs a single iterator instead of an iterator pair:
const int value = 5;
std::vector<int> vec(1, value); // single-element collection
function(std::begin(vec)); // <-- calls overload
I think I'd do this in two steps:
Define a overload of the template function that takes a container, written in terms of the iterator version.
Define a proxy class which treats an object reference as an array of size 1.
c++17 example:
#include <iterator>
#include <type_traits>
#include <vector>
#include <iostream>
// proxy object
template<class T>
struct object_as_container
{
using value_type = T;
using iterator = T*;
using const_iterator = std::add_const_t<T>;
object_as_container(value_type& val) : object_(val) {}
const_iterator begin() const { return std::addressof(object_); }
iterator begin() { return std::addressof(object_); }
const_iterator end() const { return std::next(begin()); }
iterator end() { return std::next(begin()); }
private:
value_type& object_;
};
// our function in terms of iterators
template<class Iter> void func(Iter first, Iter last)
{
while(first != last)
{
std::cout << *first++;
}
}
// our function in terms of containers
template<class Container> void func(Container&& cont)
{
func(cont.begin(), cont.end());
}
int main()
{
const int value = 5;
func(object_as_container(value));
func(std::vector { 1,2,3,4,5 });
}
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 wrote a short utility function an object to "wrap" an iterable container, so that I could walk it backwards using a range based for.
template <typename Iterable>
struct ReverseWrapper {
private:
Iterable& m_iterable;
public:
ReverseWrapper(Iterable& iterable) : m_iterable(iterable) {}
auto begin() const ->decltype(m_iterable.rbegin()) {
return m_iterable.rbegin();
}
auto end() const ->decltype(m_iterable.rend()) {
return m_iterable.rend();
}
};
template <typename Iterable>
ReverseWrapper<Iterable> reverseIterate(Iterable& list) {
return ReverseWrapper<Iterable>(list);
}
This works for C++ iterable objects, but not for static arrays. What is required for an object to support iteration using a range based for? What would be the best way to approach this problem?
The actual rule to choose begin and end functions for iterables is the following: use the class begin and end function if it has some. Use overloads of the global functions std::begin and std::end if some are provided.
Static arrays not being class/struct, they don't/can't have member functions. The functions called by the foreach loop are the global functions std::begin and std::end, taking an array as parameter. Assuming std::rbegin and std::rend existed, you would have to construct your wrapper the following way:
template <typename Iterable>
struct ReverseWrapper {
private:
Iterable& m_iterable;
public:
ReverseWrapper(Iterable&& iterable) : m_iterable(iterable) {}
auto begin() const -> decltype(rbegin(m_iterable)) {
return rbegin(m_iterable);
}
auto end() const -> decltype(rend(m_iterable)) {
return rend(m_iterable);
}
};
template<typename Iterable>
auto reverseIterate(Iterable&& list)
-> ReverseWrapper<Iterable>
{
return ReverseWrapper<Iterable>(std::forward<Iterable>(list));
}
Even though std::rbegin and std::rend exist in the c++14 standard, they are not available in the c++11 one. So, to get the above code to work with c++11, you would have to implement these functions by hand:
template<typename T, std::size_t N>
auto rbegin(T (&array)[N])
-> std::reverse_iterator<T*>
{
return std::reverse_iterator<T*>(std::end(array));
}
template<typename T, std::size_t N>
auto rend(T (&array)[N])
-> std::reverse_iterator<T*>
{
return std::reverse_iterator<T*>(std::begin(array));
}
In your code, the Iterable template parameter needs to have begin and end member functions. Normal C++ arrays do not have those functions. Instead you have to use std::begin and std::end, which are part of the C++11 standard.
However, there doesn't seem to be any std::rbegin or std::rend functions, which means you have to implement those yourself, possibly also implement the actual iterator class.
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;
}