I'm implementing a custom container with an STL-like interface. I have to provide a regular iterator and a const iterator. Most of the code for the two versions of the iterators is identical . How can I avoid this duplication?
For example, my container class is Foo, and I'm implementating FooIterator and FooConstIterator. Both of the iterators have to provide methods like operator++() which are identical.
My question is similar to How do I remove code duplication between similar const and non-const member functions?, but the answer to that one is specific to const and non-const methods, especially accessors. I don't see how that might generalize to the iterator problem.
Should I have FooIterator derive from FooConstIterator and extend it with additional non-const methods? That either leads to virtual methods or method hiding, which seem inappropriate here.
Perhaps FooIterator should contain a FooConstIterator. Although that approach does reduce implementation duplication, it seems to re-introduce a lot of boilerplate method definitions.
Is there clever template technique for generating the two iterators from a single definition? Or perhaps there's a way to--shudder--use the preprocessor to stamp out these nearly identical classes.
I've tried looking at my local STL implementation to see how it handle this. There are so many helper classes that I'm having trouble grokking the design, but it looks like the functionality is simply duplicated.
In previous projects, my custom container was built on top of a standard STL container, so I didn't have to provide my own iterators. That's not an option in this case.
[The best answer was, unfortunately, deleted by a moderator because it was a link-only answer. I understand why link-only answers are discouraged; deleting it, however, has robbed future seekers of very useful information. The link has remained stable for more than seven years and continues to work at the time of this writing.]
I strongly recommend the original Dr. Dobb's Journal article by Matt Austern entitled "The Standard Librarian: Defining Iterators and Const Iterators", January 2001. Should that link go bad, now that Dr. Dobb's has ceased operating, it's also available here.
To prevent this replacement answer from being deleted, I will summarize the solution.
The idea is to implement the iterator once as a template that takes an extra template parameter, a boolean that says whether or not this is the const version. Anywhere in the implementation where the const and non-const versions differ, you use a template mechanism to select the correct code. Matt Austern's mechanism was called choose. It looked like this:
template <bool flag, class IsTrue, class IsFalse>
struct choose;
template <class IsTrue, class IsFalse>
struct choose<true, IsTrue, IsFalse> {
typedef IsTrue type;
};
template <class IsTrue, class IsFalse>
struct choose<false, IsTrue, IsFalse> {
typedef IsFalse type;
};
If you had separate implementations for const and non-const iterators, then the const implementation would include typedefs like this:
typedef const T &reference;
typedef const T *pointer;
and the non-const implementation would have:
typedef T &reference;
typedef T *pointer;
But with choose, you can have a single implementation that selects based on the extra template parameter:
typedef typename choose<is_const, const T &, T &>::type reference;
typedef typename choose<is_const, const T *, T *>::type pointer;
By using the typedefs for the underlying types, all the iterator methods can have an identical implementation. See Matt Austern's complete example.
Since C++11/14 you can avoid such little helpers an deduce the constness directly from a boolean template.
constness.h:
#ifndef ITERATOR_H
#define ITERATOR_H
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <iterator>
struct dummy_struct {
int hello = 1;
int world = 2;
dummy_struct() : hello{ 0 }, world{ 1 }{ }
};
template< class T >
class iterable {
public:
template< bool Const = false >
class my_iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
/* deduce const qualifier from bool Const parameter */
using reference = typename std::conditional_t< Const, T const &, T & >;
using pointer = typename std::conditional_t< Const, T const *, T * >;
protected:
pointer i;
public:
my_iterator( T* _i ) : i{ reinterpret_cast< pointer >( _i ) } { }
/* SFINAE enables the const dereference operator or the non
const variant
depending on bool Const parameter */
template< bool _Const = Const >
std::enable_if_t< _Const, reference >
operator*() const {
std::cout << "Const operator*: ";
return *i;
}
template< bool _Const = Const >
std::enable_if_t< !_Const, reference >
operator*() {
std::cout << "Non-Const operator*: ";
return *i;
}
my_iterator & operator++() {
++i;
return *this;
}
bool operator!=( my_iterator const & _other ) const {
return i != _other.i;
}
bool operator==( my_iterator const & _other ) const {
return !( *this != _other );
}
};
private:
T* __begin;
T* __end;
public:
explicit iterable( T* _begin, std::size_t _count ): __begin{ _begin }, __end{ _begin + _count } { std::cout << "End: " << __end << "\n"; }
auto begin() const { return my_iterator< false >{ __begin }; }
auto end() const { return my_iterator< false >{ __end }; }
auto cbegin() const { return my_iterator< true >{ __begin }; }
auto cend() const { return my_iterator< true >{ __end }; }
};
#endif
This can be used with something like that:
#include <iostream>
#include <array>
#include "constness.h"
int main() {
dummy_struct * data = new dummy_struct[ 5 ];
for( int i = 0; i < 5; ++i ) {
data[i].hello = i;
data[i].world = i+1;
}
iterable< dummy_struct > i( data, 5 );
using iter = typename iterable< dummy_struct >::my_iterator< false >;
using citer = typename iterable< dummy_struct >::my_iterator< true >;
for( iter it = i.begin(); it != i.end(); ++it ) {
std::cout << "Hello: " << (*it).hello << "\n"
<< "World: " << (*it).world << "\n";
}
for( citer it = i.cbegin(); it != i.cend(); ++it ) {
std::cout << "Hello: " << (*it).hello << "\n"
<< "World: " << (*it).world << "\n";
}
delete[] data;
}
STL uses inheritance
template<class _Myvec>
class _Vector_iterator
: public _Vector_const_iterator<_Myvec>
In addition to the suggestion that you might templatize the constness and non-constness, you could also reduce the amount of work by taking a look at Boost.Iterator tutorial - which also mentions the same solution.
You can use CRTP and a common base to "inject" methods (but you still have to duplicate ctors in current C++), or just use the preprocessor (no shuddering required; handles ctors easily):
struct Container {
#define G(This) \
This operator++(int) { This copy (*this); ++*this; return copy; }
// example of postfix++ delegating to ++prefix
struct iterator : std::iterator<...> {
iterator& operator++();
G(iterator)
};
struct const_iterator : std::iterator<...> {
const_iterator& operator++();
G(const_iterator)
};
#undef G
// G is "nicely" scoped and treated as an implementation detail
};
Use std::iterator, the typedefs it gives you, and any other typedefs you might provide to make the macro straight-forward.
Arthor O'Dwyer is answering this in detail in his blog post:
https://quuxplusone.github.io/blog/2018/12/01/const-iterator-antipatterns/
In essence,
template<bool IsConst>
class MyIterator {
int *d_;
public:
MyIterator(const MyIterator&) = default; // REDUNDANT BUT GOOD STYLE
template<bool IsConst_ = IsConst, class = std::enable_if_t<IsConst_>>
MyIterator(const MyIterator<false>& rhs) : d_(rhs.d_) {} // OK
};
using Iterator = MyIterator<false>;
using ConstIterator = MyIterator<true>;
};
Also, add static_assert(std::is_trivially_copy_constructible_v<ConstIterator>); to your code, to make sure your iterators stay trivially copy constructible:
Conclusion: If you are implementing your own container iterators — or any other pair of types with this “one-way implicit converting” behavior, such as the Networking TS’s const_buffers_type and mutable_buffers_type — then you should use one of the patterns above to implement converting constructors without accidentally disabling trivial copyability.
Related
I am creating a function which should take as input iterators to vector
for example:
vector<int> a;
foo(a.begin(),a.end())
The vector can hold any type.
Now the simple way to do this is using templates
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I want to know if there is a way to achieve the same functionality without using templates. Since using Templates would force me to include these functions in Header file of a public API which I don't want to. So I wanted to know is there an alternate way to access the iterators without using Templates.
There are ways not to include the implementation in header files but they are not clean to implement (for instance you should know in advance the instantiations). Read here for more info about this issue:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
For instance in:
foo.h
#ifndef HI_
#define HI_
template<class Iterator>
void foo(Iterator first, Iterator last);
#endif
foo.cpp
#include "stack.h"
using namespace std;
template<class Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it != last; ++it) {
cout << *it << " ";
}
}
template
void foo( std::vector<int>::iterator first, std::vector<int>::iterator last);
template
void foo( std::vector<double>::iterator first, std::vector<double>::iterator last);
Now you can use foo function only for double and int. Other types won't link.
Hope this helps.
This is a long answer. The short answer is "type erasure"; go learn about it.
The long answer is two answers. First I cover "do you just want to be able to iterate over contiguous ints?". Then you want span. This is a really simple form of type erasure that forgets what the exact container is you are working on so long as it is contiguous and over T.
The second answer is if you actually need to deal with multiple types (not just int) and multiple kinds of containers (not just contiguous ones).
The two answers are separated by a line.
The span concept (see gsl::span) is designed for pretty much this reason. It itself is a template (over the type you are working with), but it will be a concrete instance of a template in most interfaces.
Here is a toy version of it:
template<class T>
struct span_t {
T* b = 0;
T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span_t(span_t const&)=default;
span_t& operator=(span_t const&)=default;
span_t()=default;
span_t( T* s, T* f ):b(s),e(f) {}
span_t( T* s, std::size_t l):span_t(s, s+l){}
template<std::size_t N>
span_t( T(&arr)[N] ):span_t(arr, N) {}
std::size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end()); }
T* data() const { return begin(); }
span_t without_front( std::size_t N=1 ) const {
return {std::next( begin(), (std::min)(N, size()) ), end()};
}
span_t without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(), (std::min)(N, size()) )};
}
};
we can augment it with conversion operators
namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<class...>using void_t=void;
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
template<class C>
using dot_data_r = decltype( std::declval<C>().data() );
template<class C>
using dot_size_r = decltype( std::declval<C>().size() );
template<class C>
using can_dot_data = can_apply< dot_data_r, C >;
template<class C>
using can_dot_size = can_apply< dot_size_r, C >;
can_dot_data detects via SFINAE if .data() is valid to do on an object of type C.
Now we add a constructor:
template<class T,
std::enable_if_t<
can_dot_data<T&>{}
&& can_dot_size<T&>{}
&& !std::is_same<std::decay_t<T>, span_t>{}
, int
> =0
>
span_t( T&& t ): span_t( t.data(), t.size() ) {}
which covers std::vector and std::string and std::array.
Your function now looks like:
void foo(span_t<int> s) {
for (auto&& e:s)
std::cout << s;
}
}
with use:
std::vector<int> a;
foo(a);
now, this only works for contiguous containers of a specific type.
Suppose this is not what you want. Maybe you do need to solve this for a myriad of types, and you don't want to expose everything in the header.
Then what you need to do is known as type erasure.
You need to work out what minimal set of operations you need from the provided types. Then you need to write wrappers that "type erase" these operations down to "typeless" operations.
This goes in the header, or in another helper header.
In the interface of the function, or in a header intermediate helper, you take the incoming types and do the type erasure, then pass the type-erased types into the "real" implementation.
An example of type erasure is std::function. It takes almost anything that can be invoked with a fixed signature, and turns it into a single type-erased type. Everything except how to copy, destroy and invoke an instance of the type is "forgotten" or erased.
For your case:
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I see two things that need to be erased down to; iteration, and printing.
struct printable_view_t {
void const* data = 0;
void(*print_f)(std::ostream& os, void const*) = 0;
explicit operator bool()const{return data;}
printable_view_t() = default;
printable_view_t(printable_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<T, printable_view_t>{}, int> =0
>
printable_view_t( T const& t ):
data( std::addressof(t) ),
print_f([](std::ostream& os, void const* pv){
auto* pt = static_cast<T const*>(pv);
os << *pt;
})
{}
std::ostream& operator()(std::ostream& os)const {
print_f(os, data);
return os;
}
friend std::ostream& operator<<(std::ostream& os, printable_view_t p) {
return p(os);
}
};
printable_view_t is an example of type-erasing "I can be printed".
void bar( printable_view_t p ) {
std::cout << p;
}
void test_bar() {
bar(7);
bar(3.14);
bar(std::string("hello world"));
}
The next thing we'd have to do is type erase iteration. This is harder, because we want to type erase iteration over iterating over a printable_view_t type.
Type erasing foreach is a tad easier, and often more efficient.
template<class View>
struct foreach_view_t {
void* data = 0;
void(*func)( std::function<void(View)>, void* ) = 0;
explicit operator bool()const{return data;}
foreach_view_t() = default;
foreach_view_t(foreach_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<std::decay_t<T>, foreach_view_t>{}, int> =0
>
foreach_view_t( T&& t ):
data( const_cast<std::decay_t<T>*>(std::addressof(t)) ),
func([](std::function<void(View)> f, void* pv){
auto* pt = static_cast<std::remove_reference_t<T>*>(pv);
for (auto&& e : *pt)
f(decltype(e)(e));
})
{}
void operator()(std::function<void(View)> f)const{
func(f, data);
}
};
we then daisy chain these together
void foo(foreach_view_t<printable_view_t> x) {
x([](auto p){ std::cout << p; });
}
test code:
std::vector<int> a{1,2,3};
foo(a);
Now much of the header code was "hoisted" into the type erasure types instead of a function template body. But careful choice of the points of type erasure can let you keep what you need from the types precise and narrow, and the logic of how you use those operations private.
As an example, the above code doesn't care where you are printing it to; std::cout was not part of the type erasure.
Live example.
I want to know if there is a way to achieve the same functionality without using templates. [...] I wanted to know is there an alternate way to access the iterators without using Templates.
Yes, if you use C++14, but...
Since using Templates would force me to include these functions in Header file of a public API which I don't want to.
... isn't a useful way for you because it's equivalent to use templates and you have to put it in the header file.
In C++14 you can use a lambda function with auto parameters.
auto foo = [](auto first, auto last)
{ for (auto it = first ; it != last; ++it ) std::cout << *it; };
The autos aren't template (from a formal point of view) but are equivalent and you can't declare foo in the header and develop it in a cpp file.
In responding to this question on CodeReview, I was thinking about how one might write a template function to indicate const-ness of a contained object.
To be specific, consider this templated function
#include <iostream>
#include <numeric>
#include <vector>
template <class It>
typename std::iterator_traits<It>::value_type average(It begin, It end) {
typedef typename std::iterator_traits<It>::value_type real;
real sum = real();
unsigned count = 0;
for ( ; begin != end; ++begin, ++count)
sum += *begin;
return sum/count;
}
int main()
{
std::vector<double> v(1000);
std::iota(v.begin(), v.end(), 42);
double avg = average(v.cbegin(), v.cend());
std::cout << "avg = " << avg << '\n';
}
It takes an iterator and calculates an average based on the contained numbers, but it is guaranteed not to modify the vector through the passed iterators. How does one convey this to a user of the template?
Note that declaring it like this:
template <class It>
typename std::iterator_traits<It>::value_type average(const It begin,
const It end)
doesn't work because it's not the iterator, but the thing the iterator points to, that's const. Do I have to wait for concepts to be standardized?
Note that I don't want to require const iterators, but instead to indicate that they may be safely used here. That is, rather than restricting the caller, I want to convey a promise that my code is making: "I will not modify your underlying data."
template <class ConstIt>
It's that simple. There's nothing to be enforced on the caller side here, as a non-const iterator is also usable for const access, so it's just API documentation, and that's what your choice of parameter identifier is - API documentation.
That does lead on to the question of enforcement on the callee/function side - so it can't be pretending it will only use the iterator for const access then modify elements anyway. Should you care about that, you could accept the parameter using some identifier making it clear it wasn't meant to be used everywhere throughout the function, then create a const_iterator version with a more convenient identifier. That could be tricky as in general you don't know if the iterator type is a member of a container, let alone what that container type is and whether it has a const_iterator too, so some manner of Concepts would indeed be ideal - fingers crossed for C++14. Meanwhile:
have your caller tell you the container type,
write your own traits, OR
write a simple wrapper class that holds an iterator and ensures only const access to the referenced data escapes the interface
This last wrapper approach is illustrated below (not all of the iterator API is implemented so flesh out as needed):
template <typename Iterator>
class const_iterator
{
public:
typedef Iterator iterator_type;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
// note: trying to add const to ...:reference or ..:pointer doesn't work,
// as it's like saying T* const rather than T const* aka const T*.
typedef const typename std::iterator_traits<Iterator>::value_type& reference;
typedef const typename std::iterator_traits<Iterator>::value_type* pointer;
const_iterator(const Iterator& i) : i_(i) { }
reference operator*() const { return *i_; }
pointer operator->() const { return i_; }
bool operator==(const const_iterator& rhs) const { return i_ == rhs.i_; }
bool operator!=(const const_iterator& rhs) const { return i_ != rhs.i_; }
const_iterator& operator++() { ++i_; return *this; }
const_iterator operator++(int) const { Iterator i = i_; ++i_; return i; }
private:
Iterator i_;
};
Sample usage:
template <typename Const_Iterator>
void f(const Const_Iterator& b__, const Const_Iterator& e__)
{
const_iterator<Const_Iterator> b{b__}, e{e__}; // make a really-const iterator
// *b = 2; // if uncommented, compile-time error....
for ( ; b != e; ++b)
std::cout << *b << '\n';
}
See it running at ideone.com here.
You may add some traits to see if the iterator is a const_iterator:
template <typename IT>
using is_const_iterator =
std::is_const<typename std::remove_reference<typename std::iterator_traits<IT>::reference>::type>;
And then use something like:
template <typename IT>
typename
std::enable_if<is_const_iterator<IT>::value,
typename std::iterator_traits<It>::value_type
>::type average(It begin, It end);
But this will avoid the use of iterator which are convertible to const_iterator.
So it will be better to restrict iterator when const is forbidden (as in std::sort)
It takes an iterator and calculates an average based on the contained numbers, but it is guaranteed not to modify the vector through the passed iterators. How does one convey this to a user of the template?
You could use SFINAE to disable the template when non-const iterators are passed, but that would be an unnecessary limitation.
Another way is to accept ranges instead of iterators. This way you could write:
template <class Range>
typename Range::value_type average(Range const& range);
The user can pass a container or iterator range in there.
You could try always dereferencing the iterator through some function deref().
template <typename It>
typename ::std::remove_reference<typename ::std::iterator_traits<It>::reference>::type const&
deref(It it)
{
return *it;
}
Which would guarantee the underlying value will not be modified.
As an extension to this question Are const_iterators faster?, I have another question on const_iterators. How to remove constness of a const_iterator?
Though iterators are generalised form of pointers but still const_iterator and iterators are two different things. Hence, I believe, I also cannot use const_cast<> to covert from const_iterator to iterators.
One approach could be that you define an iterator which moves 'til the element to which const_iterator points. But this looks to be a linear time algorithm.
Any idea on what is the best way to achieve this?
There is a solution with constant time complexity in C++11: for any sequence, associative, or unordered associative container (including all of the Standard Library containers), you can call the range-erase member function with an empty range:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
The range-erase member functions have a pair of const_iterator parameters, but they return an iterator. Because an empty range is provided, the call to erase does not change the contents of the container.
Hat tip to Howard Hinnant and Jon Kalb for this trick.
Unfortunately linear time is the only way to do it:
iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
where iter and constIter are suitable typedefs and d is the container over which you are iterating.
In the answers to your previous post, there were a couple of people, me included, that recommended using const_iterators instead for non-performance related reasons. Readability, traceability from the design board to the code... Using const_iterators to provide mutating access to a non-const element is much worse than never using const_iterators at all. You are converting your code into something that only you will understand, with a worse design and a real maintainability pain. Using const just to cast it away is much worse than not using const at all.
If you are sure you want it, the good/bad part of C++ is that you can always get enough rope to hang yourself. If your intention is using const_iterator for performance issues, you should really rethink it, but if you still want to shoot your foot off... well C++ can provide your weapon of choice.
First, the simplest: if your operations take the arguments as const (even if internally apply const_cast) I believe it should work directly in most implementations (even if it is probably undefined behavior).
If you cannot change the functors, then you could tackle the problem from either side: provide a non-const iterator wrapper around the const iterators, or else provide a const functor wrapper around the non-const functors.
Iterator façade, the long road:
template <typename T>
struct remove_const
{
typedef T type;
};
template <typename T>
struct remove_const<const T>
{
typedef T type;
};
template <typename T>
class unconst_iterator_type
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename remove_const<
typename std::iterator_traits<T>::value_type
>::type value_type;
typedef value_type* pointer;
typedef value_type& reference;
unconst_iterator_type( T it )
: it_( it ) {} // allow implicit conversions
unconst_iterator_type& operator++() {
++it_;
return *this;
}
value_type& operator*() {
return const_cast<value_type&>( *it_ );
}
pointer operator->() {
return const_cast<pointer>( &(*it_) );
}
friend bool operator==( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return !( lhs == rhs );
}
private:
T it_; // internal (const) iterator
};
Scott Meyer's article on preferring iterators over const_iterators answers this. Visage's answer is the only safe pre-C++11 alternative, but is actually constant time for well-implemented random access iterators, and linear time for others.
This may not be the answer you wanted, but somewhat related.
I assume you want to change the thing where the iterator points to. The simplest way I do is that const_cast the returned reference instead.
Something like this
const_cast<T&>(*it);
I believe this conversion is not needed in a well-designed program.
If you need do this - try redesigning the code.
As workaround you can use the following:
typedef std::vector< size_t > container_type;
container_type v;
// filling container code
container_type::const_iterator ci = v.begin() + 3; // set some value
container_type::iterator i = v.begin();
std::advance( i, std::distance< container_type::const_iterator >( v.begin(), ci ) );
But I think that sometimes this conversion is impossible, because your algorithms don't have access to the container.
You can subtract the begin() iterator from the const_iterator to obtain the position the const_iterator is pointing to and then add begin() back to that to obtain a non-const iterator. I don't think this will be very efficient for non-linear containers, but for linear ones such as vector this will take constant time.
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
vector<int>::iterator it = v.begin() + (ci - v.begin());
cout << *it << endl;
*it = 20;
cout << *ci << endl;
EDIT: This appears to only work for linear (random access) containers.
you can convert your const iterator value pointer to a non const value pointer and use it directly something like this
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(2);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
*const_cast<int*>(&(*ci)) = 7;
cout << *ci << endl;
I thought it would be fun to come up with a solution to this that works for containers that aren't in the standard library and don't include the erase() method.
Attempting to use this causes Visual Studio 2013 to hang on compile. I'm not including the test case because leaving it to readers who can quickly figure out the interface seems like a good idea; I don't know why this hangs on compile. This occurs even when the const_iterator is equal to begin().
// deconst.h
#ifndef _miscTools_deconst
#define _miscTools_deconst
#ifdef _WIN32
#include <Windows.h>
#endif
namespace miscTools
{
template < typename T >
struct deconst
{
static inline typename T::iterator iterator ( typename T::const_iterator*&& target, T*&& subject )
{
typename T::iterator && resultant = subject->begin ( );
bool goodItty = process < 0, T >::step ( std::move ( target ), std::move ( &resultant ), std::move ( subject ) );
#ifdef _WIN32
// This is just my habit with test code, and would normally be replaced by an assert
if ( goodItty == false )
{
OutputDebugString ( " ERROR: deconst::iterator call. Target iterator is not within the bounds of the subject container.\n" )
}
#endif
return std::move ( resultant );
}
private:
template < std::size_t i, typename T >
struct process
{
static inline bool step ( typename T::const_iterator*&& target, typename T::iterator*&& variant, T*&& subject )
{
if ( ( static_cast <typename T::const_iterator> ( subject->begin () + i ) ) == *target )
{
( *variant ) += i;
return true;
}
else
{
if ( ( *variant + i ) < subject->end () )
{
process < ( i + 1 ), T >::step ( std::move ( target ), std::move ( variant ), std::move ( subject ) );
}
else { return false; }
}
}
};
};
}
#endif
Assuming your container's const_iterator has the same layout as its iterator (a valid assumption for all STL containers), you can simply bit-cast the former to the latter:
#include <bit>
#include <vector>
void demo() {
using vec_t = std::vector<int>;
vec_t v { 1, 2, 3 };
vec_t::const_iterator c_it = v.cbegin();
vec_t::iterator it = std::bit_cast<vec_t::iterator>(c_it);
*it = 4; // OK, now v holds { 4, 2, 3 }
}
As an extension to this question Are const_iterators faster?, I have another question on const_iterators. How to remove constness of a const_iterator?
Though iterators are generalised form of pointers but still const_iterator and iterators are two different things. Hence, I believe, I also cannot use const_cast<> to covert from const_iterator to iterators.
One approach could be that you define an iterator which moves 'til the element to which const_iterator points. But this looks to be a linear time algorithm.
Any idea on what is the best way to achieve this?
There is a solution with constant time complexity in C++11: for any sequence, associative, or unordered associative container (including all of the Standard Library containers), you can call the range-erase member function with an empty range:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
The range-erase member functions have a pair of const_iterator parameters, but they return an iterator. Because an empty range is provided, the call to erase does not change the contents of the container.
Hat tip to Howard Hinnant and Jon Kalb for this trick.
Unfortunately linear time is the only way to do it:
iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
where iter and constIter are suitable typedefs and d is the container over which you are iterating.
In the answers to your previous post, there were a couple of people, me included, that recommended using const_iterators instead for non-performance related reasons. Readability, traceability from the design board to the code... Using const_iterators to provide mutating access to a non-const element is much worse than never using const_iterators at all. You are converting your code into something that only you will understand, with a worse design and a real maintainability pain. Using const just to cast it away is much worse than not using const at all.
If you are sure you want it, the good/bad part of C++ is that you can always get enough rope to hang yourself. If your intention is using const_iterator for performance issues, you should really rethink it, but if you still want to shoot your foot off... well C++ can provide your weapon of choice.
First, the simplest: if your operations take the arguments as const (even if internally apply const_cast) I believe it should work directly in most implementations (even if it is probably undefined behavior).
If you cannot change the functors, then you could tackle the problem from either side: provide a non-const iterator wrapper around the const iterators, or else provide a const functor wrapper around the non-const functors.
Iterator façade, the long road:
template <typename T>
struct remove_const
{
typedef T type;
};
template <typename T>
struct remove_const<const T>
{
typedef T type;
};
template <typename T>
class unconst_iterator_type
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename remove_const<
typename std::iterator_traits<T>::value_type
>::type value_type;
typedef value_type* pointer;
typedef value_type& reference;
unconst_iterator_type( T it )
: it_( it ) {} // allow implicit conversions
unconst_iterator_type& operator++() {
++it_;
return *this;
}
value_type& operator*() {
return const_cast<value_type&>( *it_ );
}
pointer operator->() {
return const_cast<pointer>( &(*it_) );
}
friend bool operator==( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return !( lhs == rhs );
}
private:
T it_; // internal (const) iterator
};
Scott Meyer's article on preferring iterators over const_iterators answers this. Visage's answer is the only safe pre-C++11 alternative, but is actually constant time for well-implemented random access iterators, and linear time for others.
This may not be the answer you wanted, but somewhat related.
I assume you want to change the thing where the iterator points to. The simplest way I do is that const_cast the returned reference instead.
Something like this
const_cast<T&>(*it);
I believe this conversion is not needed in a well-designed program.
If you need do this - try redesigning the code.
As workaround you can use the following:
typedef std::vector< size_t > container_type;
container_type v;
// filling container code
container_type::const_iterator ci = v.begin() + 3; // set some value
container_type::iterator i = v.begin();
std::advance( i, std::distance< container_type::const_iterator >( v.begin(), ci ) );
But I think that sometimes this conversion is impossible, because your algorithms don't have access to the container.
You can subtract the begin() iterator from the const_iterator to obtain the position the const_iterator is pointing to and then add begin() back to that to obtain a non-const iterator. I don't think this will be very efficient for non-linear containers, but for linear ones such as vector this will take constant time.
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
vector<int>::iterator it = v.begin() + (ci - v.begin());
cout << *it << endl;
*it = 20;
cout << *ci << endl;
EDIT: This appears to only work for linear (random access) containers.
you can convert your const iterator value pointer to a non const value pointer and use it directly something like this
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(2);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
*const_cast<int*>(&(*ci)) = 7;
cout << *ci << endl;
I thought it would be fun to come up with a solution to this that works for containers that aren't in the standard library and don't include the erase() method.
Attempting to use this causes Visual Studio 2013 to hang on compile. I'm not including the test case because leaving it to readers who can quickly figure out the interface seems like a good idea; I don't know why this hangs on compile. This occurs even when the const_iterator is equal to begin().
// deconst.h
#ifndef _miscTools_deconst
#define _miscTools_deconst
#ifdef _WIN32
#include <Windows.h>
#endif
namespace miscTools
{
template < typename T >
struct deconst
{
static inline typename T::iterator iterator ( typename T::const_iterator*&& target, T*&& subject )
{
typename T::iterator && resultant = subject->begin ( );
bool goodItty = process < 0, T >::step ( std::move ( target ), std::move ( &resultant ), std::move ( subject ) );
#ifdef _WIN32
// This is just my habit with test code, and would normally be replaced by an assert
if ( goodItty == false )
{
OutputDebugString ( " ERROR: deconst::iterator call. Target iterator is not within the bounds of the subject container.\n" )
}
#endif
return std::move ( resultant );
}
private:
template < std::size_t i, typename T >
struct process
{
static inline bool step ( typename T::const_iterator*&& target, typename T::iterator*&& variant, T*&& subject )
{
if ( ( static_cast <typename T::const_iterator> ( subject->begin () + i ) ) == *target )
{
( *variant ) += i;
return true;
}
else
{
if ( ( *variant + i ) < subject->end () )
{
process < ( i + 1 ), T >::step ( std::move ( target ), std::move ( variant ), std::move ( subject ) );
}
else { return false; }
}
}
};
};
}
#endif
Assuming your container's const_iterator has the same layout as its iterator (a valid assumption for all STL containers), you can simply bit-cast the former to the latter:
#include <bit>
#include <vector>
void demo() {
using vec_t = std::vector<int>;
vec_t v { 1, 2, 3 };
vec_t::const_iterator c_it = v.cbegin();
vec_t::iterator it = std::bit_cast<vec_t::iterator>(c_it);
*it = 4; // OK, now v holds { 4, 2, 3 }
}
As an extension to this question Are const_iterators faster?, I have another question on const_iterators. How to remove constness of a const_iterator?
Though iterators are generalised form of pointers but still const_iterator and iterators are two different things. Hence, I believe, I also cannot use const_cast<> to covert from const_iterator to iterators.
One approach could be that you define an iterator which moves 'til the element to which const_iterator points. But this looks to be a linear time algorithm.
Any idea on what is the best way to achieve this?
There is a solution with constant time complexity in C++11: for any sequence, associative, or unordered associative container (including all of the Standard Library containers), you can call the range-erase member function with an empty range:
template <typename Container, typename ConstIterator>
typename Container::iterator remove_constness(Container& c, ConstIterator it)
{
return c.erase(it, it);
}
The range-erase member functions have a pair of const_iterator parameters, but they return an iterator. Because an empty range is provided, the call to erase does not change the contents of the container.
Hat tip to Howard Hinnant and Jon Kalb for this trick.
Unfortunately linear time is the only way to do it:
iter i(d.begin());
advance (i,distance<ConstIter>(i,ci));
where iter and constIter are suitable typedefs and d is the container over which you are iterating.
In the answers to your previous post, there were a couple of people, me included, that recommended using const_iterators instead for non-performance related reasons. Readability, traceability from the design board to the code... Using const_iterators to provide mutating access to a non-const element is much worse than never using const_iterators at all. You are converting your code into something that only you will understand, with a worse design and a real maintainability pain. Using const just to cast it away is much worse than not using const at all.
If you are sure you want it, the good/bad part of C++ is that you can always get enough rope to hang yourself. If your intention is using const_iterator for performance issues, you should really rethink it, but if you still want to shoot your foot off... well C++ can provide your weapon of choice.
First, the simplest: if your operations take the arguments as const (even if internally apply const_cast) I believe it should work directly in most implementations (even if it is probably undefined behavior).
If you cannot change the functors, then you could tackle the problem from either side: provide a non-const iterator wrapper around the const iterators, or else provide a const functor wrapper around the non-const functors.
Iterator façade, the long road:
template <typename T>
struct remove_const
{
typedef T type;
};
template <typename T>
struct remove_const<const T>
{
typedef T type;
};
template <typename T>
class unconst_iterator_type
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename remove_const<
typename std::iterator_traits<T>::value_type
>::type value_type;
typedef value_type* pointer;
typedef value_type& reference;
unconst_iterator_type( T it )
: it_( it ) {} // allow implicit conversions
unconst_iterator_type& operator++() {
++it_;
return *this;
}
value_type& operator*() {
return const_cast<value_type&>( *it_ );
}
pointer operator->() {
return const_cast<pointer>( &(*it_) );
}
friend bool operator==( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=( unconst_iterator_type<T> const & lhs,
unconst_iterator_type<T> const & rhs )
{
return !( lhs == rhs );
}
private:
T it_; // internal (const) iterator
};
Scott Meyer's article on preferring iterators over const_iterators answers this. Visage's answer is the only safe pre-C++11 alternative, but is actually constant time for well-implemented random access iterators, and linear time for others.
This may not be the answer you wanted, but somewhat related.
I assume you want to change the thing where the iterator points to. The simplest way I do is that const_cast the returned reference instead.
Something like this
const_cast<T&>(*it);
I believe this conversion is not needed in a well-designed program.
If you need do this - try redesigning the code.
As workaround you can use the following:
typedef std::vector< size_t > container_type;
container_type v;
// filling container code
container_type::const_iterator ci = v.begin() + 3; // set some value
container_type::iterator i = v.begin();
std::advance( i, std::distance< container_type::const_iterator >( v.begin(), ci ) );
But I think that sometimes this conversion is impossible, because your algorithms don't have access to the container.
You can subtract the begin() iterator from the const_iterator to obtain the position the const_iterator is pointing to and then add begin() back to that to obtain a non-const iterator. I don't think this will be very efficient for non-linear containers, but for linear ones such as vector this will take constant time.
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
vector<int>::iterator it = v.begin() + (ci - v.begin());
cout << *it << endl;
*it = 20;
cout << *ci << endl;
EDIT: This appears to only work for linear (random access) containers.
you can convert your const iterator value pointer to a non const value pointer and use it directly something like this
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(2);
vector<int>::const_iterator ci = v.begin() + 2;
cout << *ci << endl;
*const_cast<int*>(&(*ci)) = 7;
cout << *ci << endl;
I thought it would be fun to come up with a solution to this that works for containers that aren't in the standard library and don't include the erase() method.
Attempting to use this causes Visual Studio 2013 to hang on compile. I'm not including the test case because leaving it to readers who can quickly figure out the interface seems like a good idea; I don't know why this hangs on compile. This occurs even when the const_iterator is equal to begin().
// deconst.h
#ifndef _miscTools_deconst
#define _miscTools_deconst
#ifdef _WIN32
#include <Windows.h>
#endif
namespace miscTools
{
template < typename T >
struct deconst
{
static inline typename T::iterator iterator ( typename T::const_iterator*&& target, T*&& subject )
{
typename T::iterator && resultant = subject->begin ( );
bool goodItty = process < 0, T >::step ( std::move ( target ), std::move ( &resultant ), std::move ( subject ) );
#ifdef _WIN32
// This is just my habit with test code, and would normally be replaced by an assert
if ( goodItty == false )
{
OutputDebugString ( " ERROR: deconst::iterator call. Target iterator is not within the bounds of the subject container.\n" )
}
#endif
return std::move ( resultant );
}
private:
template < std::size_t i, typename T >
struct process
{
static inline bool step ( typename T::const_iterator*&& target, typename T::iterator*&& variant, T*&& subject )
{
if ( ( static_cast <typename T::const_iterator> ( subject->begin () + i ) ) == *target )
{
( *variant ) += i;
return true;
}
else
{
if ( ( *variant + i ) < subject->end () )
{
process < ( i + 1 ), T >::step ( std::move ( target ), std::move ( variant ), std::move ( subject ) );
}
else { return false; }
}
}
};
};
}
#endif
Assuming your container's const_iterator has the same layout as its iterator (a valid assumption for all STL containers), you can simply bit-cast the former to the latter:
#include <bit>
#include <vector>
void demo() {
using vec_t = std::vector<int>;
vec_t v { 1, 2, 3 };
vec_t::const_iterator c_it = v.cbegin();
vec_t::iterator it = std::bit_cast<vec_t::iterator>(c_it);
*it = 4; // OK, now v holds { 4, 2, 3 }
}