I have a class that contains a std::vector, and another that is a custom iterator for that class. It works great for non-const methods, but when I try to create an iterator in a const method, the compiler fails because it can't convert a const_iterator to an iterator. For example, the code below fails, but if the call to ConstFunc is commented out, it compiles and runs fine.
#include <vector>
template <class T>
class FooIter {
public:
typename std::vector<T>::iterator iterator;
FooIter(std::vector<T> &vec) {iterator = vec.begin();}
};
template <class T>
class Foo {
public:
std::vector<T> vec;
Foo() {}
void NonConstFunc() {
FooIter<T> iter(vec);
}
void ConstFunc() const {
FooIter<T> iter(vec);
}
};
int main()
{
Foo<int> foo;
foo.NonConstFunc();
foo.ConstFunc();
return 0;
}
Is there a way to modify FooIter so it can serve as both iterator and const_iterator?
EDIT: A commenter asked "How do you plan to use FooIter<T> in a const method?" Below is one example.
std::vector< std::pair<unsigned, unsigned> > find() const {
std::vector< std::pair<unsigned, unsigned> > list(0);
Matrix2dIterator<T> it = this->begin(true);
Matrix2dIterator<T> itEnd = this->end(true);
for (; it != itEnd; ++it) {
if (*it) {
list.push_back(std::make_pair(it.getRow(), it.getCol()));
}
}
return list;
}
Matrix2d is "Foo", and Matrix2dIterator is "FooIter". find needs to iterate over the std::vector which holds the matrix data, but it is not changing that data.
The reason for this is, that you could modify vec and therefore your class through a std::vector<T>::iterator. So you cannot have them in a const member function. The more technical reason is that in a const member function all members are const and the std::vector has the functions
std::vector<T>::iterator begin();
std::vector<T>::const_iterator begin() const;
std::vector<T>::const_iterator cbegin() const;
so if vec is const begin() will return a const iterator which is also very sensible, since you cannot modify the vector through a const_iterator.
You can adapt your code by providing a ConstFooIter that has a member of type std::vector<T>::const_iterator this would look like the following:
#include <vector>
template <class T>
class ConstFooIter {
public:
typename std::vector<T>::const_iterator iterator;
ConstFooIter(const std::vector<T> &vec) {iterator = vec.cbegin();}
};
Alternatively, you don't template on the value_type of the vector but on the vector itself, this detects const-ness automatically:
#include <vector>
template <class T, class = std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::vector<typename T::value_type, typename T::allocator_type>>>>
class FooIter {
public:
decltype(std::declval<T>().begin()) iterator;
FooIter(T &vec) {iterator = vec.begin();}
};
template <class T>
class Foo {
public:
std::vector<T> vec;
Foo() {}
void NonConstFunc() {
FooIter iter(vec);
}
void ConstFunc() const {
FooIter iter(vec);
}
};
int main()
{
Foo<int> foo;
foo.NonConstFunc();
foo.ConstFunc();
return 0;
}
Note that this does not imply that you only have one class left. The iters in your two methods will be of different types (FooIter<std::vector<T>> vs FooIter<const std::vector<T>>). The advantage is that the compiler will do the dirty work of writing the two classes for you and hence you decrease the code duplication since the two classes are nearly the same.
This comes at a disadvantage. It is not that easy to see which variant is used right now and using a const iterator in a non-const context (which you should always do if you do not intend to modify anything) is a bit tricky since FooIter(vec) will always return the non-const variant when vec is not const.
EDIT: Added some template magic to only allow std::vector, i.e. std::set<int> s; FooIter f{s}; won't compile anymore.
You should go for one of n314159's solutions. I'm just showing what the problem is of making your FooIter work for both non-const and const vectors.
You can add an overloaded constructor to FooIter that takes a const reference:
FooIter(const std::vector<T> &vec) {iterator = vec.begin();}
This would be enough, if it were not for the fact that iterator itself is non-const, and so the compiler will rightfully complain about that. You could have two member variables, one non-const and the other const:
typename std::vector<T>::iterator iterator;
typename std::vector<T>::const_iterator const_iterator;
FooIter(std::vector<T> &vec) {iterator = vec.begin();}
FooIter(const std::vector<T> &vec) {const_iterator = vec.begin();}
But then other member functions would need to know which one to use. You could add a flag variable for that, but that would be rather inefficient; it needs more memory (apart from the duplication of the iterator itself), and it needs a check for every member function call. So the best solution is to have two separate iterator classes, one for non-const and the other for const.
maybe..?
#include <vector>
using namespace std;
template <class T>
class FooIter {
public:
const typename vector<T>::iterator itr; // const added
FooIter(vector<T> &vec) : itr{vec.begin()} {}
};
template <class T>
class Foo {
public:
vector<T> vec;
Foo() {}
void NonConstFunc() {
FooIter<T> iter(vec);
}
void ConstFunc() { // const removed, if
FooIter<T> iter(vec); // needed prefix it on each needed line
}
};
int main() {
Foo<int> foo;
foo.NonConstFunc();
foo.ConstFunc();
return 0;
}
Related
#include <iostream>
template <typename T>
struct Node
{
T value;
Node<T>* next;
};
template <typename T>
struct LinkedList
{
// head, tail....
// some implementation...
};
template<
template<typename> typename node,
typename T,
template<typename> typename iterator,
template<typename> typename const_iterator
>
struct SomeComonFunctionsBetweenIterators
{
node<T>* ptr;
// some implementation...
SomeComonFunctionsBetweenIterators(node<T>* ptr) : ptr(ptr) {}
T& operator*() { return ptr->value; }
iterator<T> GetIterator() { return iterator<T>(ptr); }
// doesn't work. want some way like this instead of passing the
// const iterator as a template argument.
//operator const_iterator<T>() { return iterator<const T>(ptr) ; }
operator const_iterator<T>() { return const_iterator<T>(ptr); }
};
template <typename T>
struct LinkedListConstIterator;
template <typename T>
struct LinkedListIterator
: public SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>
{
LinkedListIterator(Node<T>* ptr)
: SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>(ptr) {}
// some implementation...
};
template <typename T>
struct LinkedListConstIterator : public LinkedListIterator<T>
{
LinkedListConstIterator(Node<T>* ptr) : LinkedListIterator<T>(ptr) {}
const T& operator*() { return static_cast<const T&>(this->ptr->value); }
};
int main()
{
Node<int> node{ 5, nullptr };
LinkedListIterator<int> it(&node);
std::cout << *it << '\n';
LinkedListConstIterator<int> cit = it;
std::cout << *cit << '\n';
}
In this code I have a linked list and an iterator to it. Also I have a const iterator which inherits from the normal iterator and when dereferenced, returns a const T. The iterator can be for a singly linked list or a doubly linked list and most of the functions in both of them are the same (dereferencing or comparing for example). So I extracted the common functions and put it in a common struct. I want to be able to asign normal iterators to const iterators. So I pass the const iterator to the normal iterator as a template argument and define a conversion operator from the normal iterator to const iterator. This way works but it requires me to always pass the const iterator alongside the normal iterator as a template argument.
Is there any better way to implement const_iterators? instead of passing the const iterator everywhere. How the const_iterators are implemented for example in the STL containers?
How the const_iterators are implemented for example in the STL containers?
You can probably look in your implementation's header files to see how they chose to do it. It will depend on the container type and its internal data structure. But the common pattern I've seen is that there's some private template that can take either non-const T or const T, and that will be used as a base or member of the actual distinct iterator types. One catch is that a specific type from the data structure needs to be used, independently of the type the iterator classes expose. In your example, Node<T> and Node<const T> are not interoperable, so SomeComonFunctionsBetweenIterators could work, but should probably have the node type as a template argument independent of the value type T.
But for an easy way to define iterator types, I always turn to Boost.Iterator's iterator_facade or iterator_adaptor. They take care of a lot of the technical requirements about iterators, letting the author just fill in the behavioral bits. iterator_facade is for implementing something "from scratch", and iterator_adaptor is for the common case of an iterator that contains and wraps another iterator.
The Boost documentation for iterator_facade discusses a way to define related iterator and const_iterator types. (Though their decision to make the iterators interoperable as long as the pointers can convert probably wouldn't be appropriate for iterators from containers.)
Using iterator_facade will also give a bunch of things algorithms may expect of iterators but missing from your code shown, like making std::iterator_traits work, equality and inequality, and other fiddly details.
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
template <typename T>
struct Node
{
T value;
Node* next;
};
template <typename NodeType, typename ValueType, typename ContainerType>
class TLinkedListIterator :
public boost::iterator_facade<
TLinkedListIterator<NodeType, ValueType, ContainerType>, // CRTP Derived type
ValueType, // Iterator's value_type
std::forward_iterator_tag // Category
>
{
public:
TLinkedListIterator() : m_node(nullptr) {}
protected:
explicit TLinkedListIterator(NodeType* node) : m_node(node) {}
private:
friend boost::iterator_core_access;
friend ContainerType;
template <typename N, typename V, typename C> friend class TLinkedListIterator;
ValueType& dereference() const { return m_node->value; }
void increment() { m_node = m_node->next; }
// Templating allows comparison between iterator and const_iterator
// in any combination.
template <typename OtherValueType>
bool equal(const TLinkedListIterator<NodeType, OtherValueType, ContainerType>& iter)
{ return m_node == iter.m_node; }
NodeType m_node;
};
template <typename T>
class LinkedList
{
public:
using iterator = TLinkedListIterator<Node<T>, T, LinkedList>;
class const_iterator
: public TLinkedListIterator<Node<T>, const T, LinkedList>
{
private:
using BaseType = TLinkedListIterator<Node<T>, const T, LinkedList>;
public:
const_iterator() = default;
// Converting constructor for implicit conversion from iterator
// to const_iterator:
const_iterator(const iterator& iter)
: BaseType(iter.m_node) {}
protected:
explicit const_iterator(Node<T>* node)
: BaseType(node) {}
friend LinkedList<T>;
};
iterator begin() { return iterator(get_head()); }
iterator end() { return iterator(); }
const_iterator begin() const { return const_iterator(get_head()); }
const_iterator end() const { return const_iterator(); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
// ...
};
I have the following class that wraps a C++ map. I'd like to override just the iterator dereference, to return the map's value only instead of the key. Is this possible at all, without having to re-implement the entire std::map iterator (which I should probably avoid as much as possible)?
Here it is:
#include <map>
using std::map;
class X {
using Type = map<int, double>;
using const_iterator = typename Type::const_iterator;
public:
void insert(int key, double value) {
my_map[key] = value;
}
const_iterator cbegin() const { return my_map.cbegin(); }
const_iterator cend() const { return my_map.cend(); }
const_iterator begin() const { return my_map.cbegin(); }
const_iterator end() const { return my_map.cend(); }
private:
Type my_map;
};
int main() {
X x;
double i;
for (const auto& it : x) {
i = it.second; // works
i = it; // fails
}
}
You pretty much do need to implement an entire iterator type to provide new iterator behavior. Luckily, Boost has a couple of tools that can make this much easier: boost::iterator_facade is a tool for creating an iterator type, which takes care of satisfying all the requirement details for the various types of Iterator as defined by the Standard. And for the common case where you want to create an iterator which wraps another iterator, overriding just pieces of its functionality, there's boost::iterator_adaptor.
So you could define your X::const_iterator like this:
#include <map>
#include <boost/iterator_adaptor.hpp>
using std::map;
class X {
using Type = map<int, double>;
public:
class const_iterator : public boost::iterator_adaptor<
const_iterator, // Derived iterator type, for CRTP
typename Type::const_iterator, // Wrapped iterator type
const double> // Value type
{
public:
const_iterator() {}
private:
// Allow X to create X::const_iterator from Type::const_iterator:
explicit const_iterator(typename Type::const_iterator map_iter)
: iterator_adaptor(map_iter) {}
friend X;
// Define the dereference operation:
const double& dereference() const
{ return base()->second; }
// Allow boost's internals to use dereference():
friend boost::iterator_core_access;
};
const_iterator cbegin() const { return const_iterator(my_map.cbegin()); }
};
...
(I intentionally changed the access of the name X::const_iterator from private to public. Someone may want to explicitly name that iterator type.)
Borrowing from Yakk's answer here you can easily modify it to suite your needs.
template<class T>
T value_of(T t) { return std::move(t); }
template<class K, class V>
V value_of(std::pair<K, V> const& p) { return p.second; }
template<class It>
struct range_t {
It b;
It e;
It begin() const { return b; }
It end() const { return e; }
};
template<class T>
struct value_t {
T t;
void operator++(){ t++; }
auto operator*() { return value_of(*t); }
friend bool operator==(value_t const& left, value_t const& right)
{ return left.t == right.t; }
friend bool operator!=(value_t const& left, value_t const& right)
{ return left.t != right.t; }
};
template<class T>
range_t<value_t<T>> values_over(T b, T e) {
return {{b}, {e}};
}
template<class C>
auto values_of(C& c) {
using std::begin; using std::end;
return values_over(begin(c), end(c));
}
int main() {
X x;
double i;
for (double const& it : values_of(x)) {
i = it;
}
}
Suppose I have a nested structure, say some class that contains some other classes:
struct Obj
{
std::vector<T> mVector; // T is large
};
std::vector<Obj> myVector;
I want to use some existing function, let's call it std::find_if, to find occurrences of T that match some criterion, etc. Many Standard Library functions (std::find_if included) require iterable ranges as inputs, so simply passing myVector iterators into these functions will cause the rows, not the elements, to be traversed.
Performance is also a concern so I don't want to have to reconstruct an entire vector of pointers or, worse, copy the objects themselves just in order to run these functions across the elements.
Having used boost::adaptors for various useful tasks such as filtering or indirecting containers without reconstructing them first, I figure I basically want to be able to do something like this:
auto myRange = boost::adaptors::nested(myVector, functor);
Where functor is some lambda that yanks nested ranges out of each row in my matrix, something like this:
auto functor = [](auto& it) { return boost::iterator_range(it.begin(), it.end(); }
Of course, boost::adaptors::nested doesn't exist. So how can I flatten this 2D array without copying Obj and without creating another flattened container first? The answer should be reasonably efficient while minimising the amount of code and boilerplate.
The answer is indeed to write an adaptor. It will need to keep track of the iterator in the outer container, and an iterator within the inner container.
Here is an example implementation, that only supports forward_iterator semantics, and const access — I'll leave a more complete implementation to you!
#include <cstddef>
#include <iterator>
template <typename V>
struct flat_view {
V &v;
typedef typename V::value_type inner_type;
typedef typename inner_type::value_type value_type;
typedef typename inner_type::reference reference;
typedef typename inner_type::const_reference const_reference;
struct const_iterator {
typedef std::forward_iterator_tag iterator_category;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::value_type value_type;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::pointer pointer;
typedef typename std::iterator_traits<typename inner_type::const_iterator>::reference reference;
typedef ptrdiff_t difference_type;
typename inner_type::const_iterator i,i_end;
typename V::const_iterator o,o_end;
bool at_end;
const_iterator(): at_end(true) {}
const_iterator(typename V::const_iterator vb,typename V::const_iterator ve):
o(vb), o_end(ve), at_end(vb==ve)
{
if (!at_end) {
i=vb->begin();
i_end=vb->end();
}
}
const_iterator &operator++() {
if (at_end) return *this;
if (i!=i_end) ++i;
while (!at_end && i==i_end) {
if (++o==o_end)
at_end=true;
else {
i=o->begin();
i_end=o->end();
}
}
return *this;
}
const_iterator &operator++(int) {
iterator c(*this);
++*this;
return c;
}
bool operator==(const const_iterator &x) const {
return (at_end && x.at_end) || (o==x.o && i==x.i);
}
bool operator!=(const const_iterator &x) const { return !(*this==x); }
reference operator*() const { return *i; }
pointer operator->() const { return &*i; }
};
typedef const_iterator iterator;
explicit flat_view(V &v_): v(v_) {};
iterator begin() const { return iterator(v.begin(),v.end()); }
iterator end() const { return iterator(); }
const_iterator cbegin() const { return const_iterator(v.begin(),v.end()); }
const_iterator cend() const { return const_iterator(); }
};
template <typename V>
flat_view<V> make_flat_view(V &v) { return flat_view<V>(v); }
Quick demo:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::vector<double>> v={
{1,2,3,4},
{},
{10,9,8,7},
{5,6}
};
auto f=make_flat_view(v);
std::copy(f.begin(),f.end(),std::ostream_iterator<double>(std::cout," "));
std::cout << "\n";
}
produces:
1 2 3 4 10 9 8 7 5 6
I need to define a get method in two different ways. One for simple types T. And once for std::vector.
template<typename T>
const T& Parameters::get(const std::string& key)
{
Map::iterator i = params_.find(key);
...
return boost::lexical_cast<T>(boost::get<std::string>(i->second));
...
}
How can I specialize this method for std::vector. As there the code should look something like this:
template<typename T>
const T& Parameters::get(const std::string& key)
{
Map::iterator i = params_.find(key);
std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
std::vector<T> ret(temp.size());
for(int i=0; i<temp.size(); i++){
ret[i]=boost::lexical_cast<T>(temp[i]);
}
return ret;
}
But I do not know how to specialize the function for this. Thanks a lot.
Don't specialize function template.
Why Not Specialize Function Templates?
Template Specialization and Overloading
Instead, use overload.
Write a function template get_impl to handle the general case, and overload (not specialize) this to handle the specific case, then call get_impl from get as:
template<typename T>
const T& Parameters::get(const std::string& key)
{
//read the explanation at the bottom for the second argument!
return get_impl(key, static_cast<T*>(0) );
}
And here goes the actual implementations.
//general case
template<typename T>
const T& Parameters::get_impl(const std::string& key, T*)
{
Map::iterator i = params_.find(key);
return boost::lexical_cast<T>(boost::get<std::string>(i->second));
}
//this is overload - not specialization
template<typename T>
const std::vector<T>& Parameters::get_impl(const std::string& key, std::vector<T> *)
{
//vector specific code
}
The static_cast<T*>(0) in get is just a tricky way to disambiguate the call. The type of static_cast<T*>(0) is T*, and passing it as second argument to get_impl will help compiler to choose the correct version of get_impl. If T is not std::vector, the first version will be chosen, otherwise the second version will be chosen.
Erm. call it something else? e.g.
template<typename T>
const T& Parameters::getVector(const std::string& key)
{
Map::iterator i = params_.find(key);
std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
// T is already a vector
T ret; ret.reserve(temp.size());
for(int i=0; i<temp.size(); i++){
ret.push_back(boost::lexical_cast<typename T::value_type>(temp[i]));
}
return ret;
}
You'll have to call this as:
foo.getVector<std::vector<int> > ("some_key");
Nothing in your question precludes this.
Now, if you really do need to use get(), then you have to rely on partially specializing a structure, as function partial specialization is not supported by the language.
This is a lot more complicated, for example:
template <typename T>
struct getter
{
const T& operator()(std::string const& key)
{
// default operations
}
};
// Should double check this syntax
template <typename T>
struct getter<std::vector<T, std::allocator<T> > >
{
typedef std::vector<T, std::allocator<T> > VecT;
const VecT& operator()(std::string const& key)
{
// operations for vector
}
};
Then in you method becomes:
template<typename T>
const T& Parameters::get(const std::string& key)
{
return getter<T>()(key); // pass the structures getter needs?
}
I have a class like this:
template<class T>
class AdjacencyList {
public:
void delete_node(const T&);
protected:
const typename std::vector<T>::const_iterator _iterator_for_node(
const std::vector<T>&, const T&
);
};
template<class T>
void AdjacencyList<T>::delete_node(const T& node) {
_nodes.erase(_iterator_for_node(_nodes, node));
}
template<class T>
const typename std::vector<T>::const_iterator AdjacencyList<T>::_iterator_for_node(
const std::vector<T>& list, const T& node
) {
typename std::vector<T>::const_iterator iter =
std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
Apparently, std::vector::erase() cannot take a const_iterator, but std::find() requires one. I could cast away the const-ness of the iterator returned by std::find() when feeding it to std::vector::erase(), but Effective C++ taught me to regard const_cast with suspicion.
Is there another way to do this? I can't believe that something as common as removing an element from a vector should require type gymnastics. :)
I suggest you change or overload your _iterator_for_node() function to accept a non-const reference to the list. The reason std::find returns a const_iterator is because the list itself is const, and therefore begin() and end() return const_iterators.
As an aside, const_cast<> won't actually convert a const_iterator to an iterator as the 'const' is just part of the name, not a CV-qualifier.
Also, you're not technically supposed to prefix names with an underscore, as this is reserved for implementations. (it will generally work in practice)
Aside from my direct modification of the code, here's an idea:
Instead of a member function _iterator_for_node which
has const issues
is uselessly tightly bound to a particular container type (inducing a typename template resolution mess)
does nothing more than std::find and throw an exception if not found
I suggest creating the following static (global/namespace) function instead:
template<class It, class T>
It checked_find(It begin, It end, const T& node)
{
It iter = std::find(begin, end, node);
if (iter != end)
return iter;
throw NoSuchNodeException();
}
It will work with any iterator type (including non-STL, input stream iterators, forward only, const, reverse iterators... you name it) and it doesn't require explicit distinction between const/non const versions :)
With it,
a working version of your code sample would just read
template<class T>
class AdjacencyList {
std::vector<T> _nodes;
public:
void delete_node(const T& node)
{ _nodes.erase(checked_find(_nodes.begin(), _nodes.end(), node)); }
};
Note the code reduction. Always the good sign
Cheers
There seems to be quite some confusion between const elements, and const iterators in your code.
Without looking in to the use case, I propose the following 'fix' to make things compile:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct NoSuchNodeException {};
template<class T>
class AdjacencyList {
std::vector<T> _nodes;
public:
void delete_node(const T&);
protected:
typename std::vector<T>::iterator _iterator_for_node(std::vector<T>&, const T&);
typename std::vector<T>::const_iterator _iterator_for_node(const std::vector<T>&, const T&) const;
};
template<class T>
void AdjacencyList<T>::delete_node(const T& node) {
_nodes.erase(_iterator_for_node(_nodes, node));
}
template<class T>
typename std::vector<T>::iterator AdjacencyList<T>::_iterator_for_node(std::vector<T>& list, const T& node)
{
typename std::vector<T>::iterator iter = std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
template<class T>
typename std::vector<T>::const_iterator AdjacencyList<T>::_iterator_for_node(const std::vector<T>& list, const T& node) const
{
typename std::vector<T>::const_iterator iter = std::find(list.begin(), list.end(), node);
if (iter != list.end())
return iter;
throw NoSuchNodeException();
}
int main()
{
AdjacencyList<int> test;
test.delete_node(5);
}