I am definining a custom iterator
class row_iterator {
// To iterate over nodes.
friend class Hamiltonian;
public:
typedef row_iterator self_type;
typedef int value_type;
typedef std::forward_iterator_tag iterator_category;
row_iterator( const Bipartite & B ) : _B( other._B ) , _i( 0 ) {}
row_iterator( const Bipartite & B , const int i ) : _B( other._B ) , _i( i ) {}
row_iterator( const self_type & other ) : _B( other._B ) , _i( other._i ) {}
self_type operator=( const self_type & other ) { _B = other._B; _i = other._i; return ( * this ); }
self_type operator++() { _i++; return ( * this ); } // PREFIX
self_type operator++( int junk ) { self_type tmp = ( * this ); _i++; return tmp; } // POSTFIX
value_type & operator*() { return _i; }
//value_type * operator->() { return & _i; }
bool operator==( const self_type & rhs ) { return ( _i == rhs._i ) and ( _B == rhs._B ); }
bool operator!=( const self_type & rhs ) { return ( _i != rhs._i ) or ( _B != rhs._B ); }
operator bool() { return _i < _B.num_rows(); }
void test_func() {
int i = ( * this );
bool b = ( * this );
}
private:
Bipartite & _B;
int _i;
};
Pay attention to the function test_func(). Now the question...
If I write
int i = ( * this );
I assume that int operator*() is called. On the other hand, if I write
bool b = ( * this );
I assume that operator bool() is called. Is this the case?
EDIT: Here I add the test that checks that the voted answer is correct.
#include <iostream>
class iter {
public:
typedef iter self_type;
typedef int value_type;
typedef std::forward_iterator_tag iterator_category;
iter( int imax ) : _i( 0 ) , _imax( imax ) {}
value_type operator*() { return _i; }
self_type operator++() { _i++; return ( * this ); } // PREFIX
self_type operator++( int junk ) { self_type tmp = ( * this ); ++( * this ); return tmp; } // POSTFIX
operator bool() { return _i < _imax; }
void test() {
bool b = ( * this );
int q = ( * this );
int i = ( * ( * this ) );
std::cout << "b = " << b << " , q = " << q << " , i = " << i << std::endl;
}
private:
int _i;
int _imax;
};
int main( void ) {
iter it( 10 );
while ( ( bool ) it ) {
it.test();
it++;
}
}
The output, reads:
b = 1 , q = 1 , i = 0
b = 1 , q = 1 , i = 1
b = 1 , q = 1 , i = 2
b = 1 , q = 1 , i = 3
b = 1 , q = 1 , i = 4
b = 1 , q = 1 , i = 5
b = 1 , q = 1 , i = 6
b = 1 , q = 1 , i = 7
b = 1 , q = 1 , i = 8
b = 1 , q = 1 , i = 9
Your second assumption is correct. Your first is not.
You must keep in mind that the type of this is row_iterator*, thus, the result type of *this is row_iterator, which, due to the existence of your operator bool() can be contextually converted to bool which is what happens in your second assignment (bool b = *this).
In your first assignment (int i = (*this)) there is no suitable conversion from row_iterator to int. There is, however, a conversion to bool and converting a bool to an int is possible too, so in its current state, your first assignment will result in i being 1 if operator bool() returns true and 0 otherwise.
In order to fix this, you need to dereference this twice.
To elaborate, implicit conversion (which is what's happening here) consists of up to three conversions:
zero or one standard conversion sequence
zero or one user-defined conversion
zero or one standard conversion sequence.
Standard conversion sequences consist of:
zero or one lvalue transformation
zero or one numeric promotion or conversion
zero or one function pointer conversion (c++17 and up )
zero or one qualification adjustment
Since the standard conversion sequence does not allow pointers to be dereferenced, the only way dereferencing can occur during implicit conversion is if it is done in a user-defined conversion function.
Related
I got a class Matrix with a member std::list<Element> listMatrix;. Element is a a class with 3 int members line, column, value. I save in the list, elements of a matrix that are not 0 by saving the line, column and the value of the respectively element. I want to overload the operator [][] so I can do something like Matrix a; a[2][3] = 5;. I know you can't overload [][] directly.
Do overload Element& operator()(int, int) (and the const variant) so you can write
matrix(2, 3) = 5;
If you absolutely need the [2][3] syntax, you'd need to define a proxy class so matrix[2] return a proxy value and proxy[3] return the desired reference. But it comes with a lot of problems. The basic idea would be:
class naive_matrix_2x2
{
int data[4];
struct proxy
{
naive_matrix_2x2& matrix;
int x;
int& operator[](int y) { return matrix.data[x*2+y]; }
};
public:
proxy operator[](int x) { return {*this, x}; }
};
Full demo: https://coliru.stacked-crooked.com/a/fd053610e56692f6
The list is not a suitable container for using the subscript operator because it has no direct access to its elements without moving an iterator through the list.
So the operator will be inefficient.
It is better to use the standard container std::vector that already has the subscript operator.
Nevertheless answering your question the operator can be defined the following way. You can add to the operators an exception then an index will point outside the list.
#include <iostream>
#include <list>
struct A
{
int x, y, z;
int & operator []( size_t n )
{
return n == 0 ? x : n == 1 ? y : z;
}
const int & operator []( size_t n ) const
{
return n == 0 ? x : n == 1 ? y : z;
}
};
struct B
{
std::list<A> lst;
A & operator []( size_t n )
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
const A & operator []( size_t n ) const
{
auto it = std::begin( lst );
for ( ; n; n-- ) std::advance( it, 1 );
return *it;
}
};
int main()
{
B b = { { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } } };
std::cout << b[0][0] << '\n';
std::cout << b[0][1] << '\n';
std::cout << b[0][2] << '\n';
b[2][1] += 20;
std::cout << b[2][1] << '\n';
}
The program output is
1
2
3
28
According to this question/answer in stackoverflow, it is not possible to directly rewrite C++ nested typedefs in cython. I have such a problem and I don't know which is the right/optimal way to proceed.
Let me be more specific with an example. Below, you can find the content of two C++ files (one header.h and one .cpp) and of two corresponding cython files (one .pxd and one .pyx). In the C++ header file called cpp_graph.h you can see nested typedef declarations; for example, that corresponding to Graph::iterator::nn_iterator. I don't know how to expose that in the corresponding graph.pxd file. Or, in other words, I don't know what is the "official" or "standard" way to do it.
Some relevant information. If you check the cython wrapper for STL you can find nested typedefs. For example here in the utility.pxd or here in the vector.pxd file. However, those nested usages of ctypedef are used for template declarations only. Is it the case that nested typedefs work for template declarations only in cython?
The C++ header file:
// file : cpp_graph.h
#ifndef Included_cpp_graph
#define Included_cpp_graph
#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"
#ifndef Defined_bint
#define Defined_bint
typedef int bint;
#endif
class Graph {
public:
typedef std::set< int > t_nn;
typedef std::set< int >::iterator nn_iterator;
typedef std::map< int , t_nn > t_node_to_nn;
class iterator
{
// To iterate over nodes.
friend class Graph;
public:
typedef iterator self_type;
typedef int value_type;
typedef int & reference;
typedef int * pointer;
typedef t_node_to_nn::iterator map_iterator;
typedef std::forward_iterator_tag iterator_category;
iterator( map_iterator map_it ) : _map_it( map_it ) { }
self_type operator++() { _map_it++; return *this; } // PREFIX
self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX
value_type operator*() { return ( * _map_it ).first; } // Return the index "i"
Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
bool operator==( const self_type & rhs ) { return _map_it == rhs._map_it; }
bool operator!=( const self_type & rhs ) { return _map_it != rhs._map_it; }
private:
map_iterator _map_it;
};
class const_iterator
{
friend class Vertex;
public:
typedef const_iterator self_type;
typedef int value_type;
typedef int & reference;
typedef int * pointer;
typedef t_node_to_nn::iterator map_iterator;
typedef std::forward_iterator_tag iterator_category;
const_iterator( map_iterator map_it ) : _map_it( map_it ) { }
self_type operator++() { _map_it++; return *this; } // PREFIX
self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX
const value_type operator*() { return ( * _map_it ).first; } // Return the index "i"
const Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
bool operator==( const self_type& rhs ) { return _map_it == rhs._map_it; }
bool operator!=( const self_type& rhs ) { return _map_it != rhs._map_it; }
private:
map_iterator _map_it;
};
iterator begin() { _node_to_nn.begin(); }
iterator end() { _node_to_nn.end(); }
const_iterator begin() const { _node_to_nn.begin(); }
const_iterator end() const { _node_to_nn.end(); }
nn_iterator nn_begin( int i ) { assert( has_node( i ) ); return _node_to_nn[ i ].begin(); }
nn_iterator nn_end( int i ) { assert( has_node( i ) ); return _node_to_nn[ i ].end(); }
Graph() : _num_links( 0 ) {}
~Graph() { _node_to_nn.clear(); _num_links = 0; }
Graph & subgraph( std::set< int > & nodes ) {
Graph * S = new Graph();
for ( std::set< int >::iterator n_it = nodes.begin() ; n_it != nodes.end() ; n_it++ ) {
int i = ( * n_it );
assert( has_node( i ) );
for ( nn_iterator j_it = nn_begin( i ) ; j_it != nn_end( i ) ; j_it++ ) {
int j = ( * j_it );
if ( nodes.count( j ) > 0 ) { S -> add_link( i , j ); }
}
}
return ( * S );
}
int num_nodes() { return _node_to_nn.size(); }
int num_links() { return _num_links; }
int degree( int i ) { return _node_to_nn[ i ].size(); }
double avrg_degree() { return ( ( double ) 2 * num_nodes() ) / ( ( double ) _num_links ); }
bool has_node( int i ) { return _node_to_nn.count( i ) > 0; }
bool has_nn( int i , int j ) {
if ( has_node( i ) ) { return _node_to_nn[ i ].count( j ) > 0; }
return false;
}
bool has_link( int i , int j ) { return has_nn( i , j ); }
void add_node( int i ) { _node_to_nn[ i ].count( 0 ); } // Trick...
void add_link( int i , int j ) {
if ( has_link( i , j ) ) { return; }
_node_to_nn[ i ].insert( j );
_node_to_nn[ j ].insert( i );
_num_links += 1;
}
void del_link( int i , int j ) {
if ( has_link( i , j ) ) {
_node_to_nn[ i ].erase( j );
_node_to_nn[ j ].erase( i );
_num_links -= 1;
}
}
void del_node( int i ) {
iterator i_it = _node_to_nn.find( i );
for( nn_iterator j_it = i_it -> begin() ; j_it != i_it -> end() ; j_it++ ) { del_link( i , ( * j_it ) ); }
_node_to_nn.erase( i_it._map_it );
}
void clear_node( int i ) { del_node( i ); add_node( i ); } // Trick...
private:
t_node_to_nn _node_to_nn;
int _num_links;
};
std::ostream& operator<<( std::ostream& os , Graph & G );
typedef Graph::t_nn Graph_t_nn
typedef
#endif // Included_cpp_graph
The C++ .cpp file:
// cpp_graph.cpp
#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"
#include "cpp_graph.h"
std::ostream& operator<<( std::ostream& os , Graph & G ) {
os << "Graph{";
// Print nodes.
for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
int i = ( * i_it );
os << " " << patch::to_string( i );
}
os << " |";
// Print edges.
for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
int i = ( * i_it );
for ( Graph::nn_iterator j_it = G.nn_begin( i ) ; j_it != G.nn_end( i ) ; j_it++ ) {
int j = ( * j_it );
if ( i < j ) { os << " " + patch::to_string( i ) << ":" << patch::to_string( j ); }
}
}
os << " }"; // << std::endl;
return os;
}
// === For testing purposes ===.
/*
int main() {
Graph G;
G.add_link( 1 , 2 );
G.add_link( 1 , 3 );
G.add_link( 2 , 3 );
G.add_link( 3 , 4 );
G.add_link( 4 , 5 );
G.add_link( 4 , 6 );
G.add_link( 5 , 6 );
std::cout << G << std::endl;
G.del_link( 3 , 4 );
std::cout << G << std::endl;
G.del_node( 3 );
std::cout << G << std::endl;
G.clear_node( 2 );
std::cout << G << std::endl;
G.add_link( 100 , 101 );
std::cout << G << std::endl;
std::cout << "N = " << G.num_nodes() << " M = " << G.num_links() << std::endl;
}
*/
The cython .pxd file:
# file : graph.pxd
# === Cython cimports ===
from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
ctypedef cset[ int ].iterator nn_iterator
ctypedef cmap[ int , t_nn ] t_node_to_nn
cppclass iterator:
#friend class Graph;
#public:
typedef iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
value_type operator*()
Graph::t_nn * operator->()
bool operator==( const self_type & rhs )
bool operator!=( const self_type & rhs )
#private:
# map_iterator _map_it;
cppclass const_iterator:
#friend class Vertex;
#public:
typedef const_iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
const_iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
const value_type operator*()
const Graph::t_nn * operator->()
bool operator==( const self_type& rhs )
bool operator!=( const self_type& rhs )
#private:
# map_iterator _map_it;
iterator begin()
iterator end()
const_iterator begin() const
const_iterator end() const
nn_iterator nn_begin( int i )
nn_iterator nn_end( int i )
Graph()
~Graph()
Graph & subgraph( std::set< int > & nodes )
int num_nodes()
int num_links()
int degree( int i )
double avrg_degree()
bool has_node( int i )
bool has_nn( int i , int j )
bool has_link( int i , int j )
void add_node( int i )
void add_link( int i , int j )
void del_link( int i , int j )
void del_node( int i )
void clear_node( int i )
#private:
#t_node_to_nn _node_to_nn;
#int _num_links;
std::ostream& operator<<( std::ostream& os , Graph & G )
# === Python Wrapper for the C++ Graph class ===
cdef class PyGraph:
# === Data-members ===
# Pointer to a C++ Graph object.
cdef Graph * _c_graph
# === Function-members ===
# # graph.pyx
And the cython .pyx file:
# file : graph.pyx
# === Cython cimports ===
from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc
# === Ctypedefs for Graph class ===
# # graph.pxd
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph2.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
ctypedef cset[ int ].iterator nn_iterator
ctypedef cmap[ int , t_nn ] t_node_to_nn
cppclass iterator:
#friend class Graph;
#public:
typedef iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
value_type operator*()
Graph::t_nn * operator->()
bool operator==( const self_type & rhs )
bool operator!=( const self_type & rhs )
#private:
# map_iterator _map_it;
cppclass const_iterator:
#friend class Vertex;
#public:
typedef const_iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
const_iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
const value_type operator*()
const Graph::t_nn * operator->()
bool operator==( const self_type& rhs )
bool operator!=( const self_type& rhs )
#private:
# map_iterator _map_it;
iterator begin()
iterator end()
const_iterator begin() const
const_iterator end() const
nn_iterator nn_begin( int i )
nn_iterator nn_end( int i )
Graph()
~Graph()
Graph & subgraph( std::set< int > & nodes )
int num_nodes()
int num_links()
int degree( int i )
double avrg_degree()
bool has_node( int i )
bool has_nn( int i , int j )
bool has_link( int i , int j )
void add_node( int i )
void add_link( int i , int j )
void del_link( int i , int j )
void del_node( int i )
void clear_node( int i )
#private:
#t_node_to_nn _node_to_nn;
#int _num_links;
# === Python Wrapper for the C++ Graph class ===
cdef class PyGraph:
# === Data-members ===
# # graph.pxd
# === Function-members ===
def __cinit__( self ):
self._c_graph = new Graph()
def __dealloc__( self ):
del self._c_graph
# TODO : implement the methods for adding and deleting nodes/links.
Finally, when I attempt to compile/build this, I get the following error:
###########################################################
# setup build_ext...
###########################################################
Error compiling Cython file:
------------------------------------------------------------
...
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph2.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
^
------------------------------------------------------------
ExcessDegreeModel/graph.pxd:51:8: Expected an identifier, found 'ctypedef'
...
I have gotten nested definitions to work using the namespace keyword, specifying the nested declaration. Like, if you have e.g. the following in a C++ header named mystuff.hpp:
namespace MyStuff {
struct Outer {
struct Inner {
int value;
};
Inner member;
};
}
… you can encython those structures like so:
cdef extern from "mystuff.hpp" namespace "MyStuff::Outer":
cppclass Inner:
int value
cdef extern from "mystuff.hpp" namespace "MyStuff":
cppclass Outer:
Inner member
… it reads more coherently if you actually have everything in C++-land wrapped in a namespace, as written (otherwise the second cdef has no namespace in its declaration, which looks wierder IMO).
I have a number of real-world currently-working examples of this: one such example is here, another one is here.
I'm trying to create a macro to replace the for-loop
I want it to work like this:
f(var, start, Eend)
where var is the name of the loop variable, the start is the value where it begins and end, the value where it stops. The E is a symbol that can exist or not. If it exist, it is =
my macro is actually like this:
#define f(var, s, e) for(int var = s, kx = (s<e? 1 : -1); var != e; var += kx)
but this definition cannot afford = yet, so I want to extend it like this:
f(i, 10, =15) cout<<" "<<i;
output: 10 11 12 13 14 15
My question is if it's possible to remove the first char of the Eend argument of macro.
I can discover if it's equal using
#Eend[0] == '='
but after I cant use Eend to compare with s and find out if I must use ++ or --
This is what I want:
#define f(var, s, Eend)
for(int var = s, kx = s<end? 1:-1, LIM = #Eend[0] == '='? end+kx : end; var!=end; var += kx)
where end is Eend without the '=' (if it exists)
For your macro question you can simply define two macros, with slightly different (hopefully mnemonic) names.
E.g., if I understand the intention correctly,
#define xf(var, s, e) for(int var = s, kx = (s<e? 1 : -1); var != e; var += kx)
#define f(var, s, e) for(int var = s, kx = (s<e? 1 : -1), e2 = e + kx; var != e2; var += kx)
If the redundancy of that is not palatable, then you can express them in terms of a third common implementation macro.
Doing this without a macro is more work, but you only have to do the definition work once.
And you avoid possible name collisions for the macro.
E.g. it can go like this:
enum From { from };
enum To { to };
enum To_before { to_before };
class Sequence
{
private:
int first_;
int after_;
int delta_;
public:
class Iter
{
friend class Sequence;
private:
Sequence const* p_seq_;
int current_;
Iter( Sequence const& seq )
: p_seq_( &seq )
, current_( seq.first_ )
{}
Iter( Sequence const& seq, int const current )
: p_seq_( &seq )
, current_( current )
{}
public:
friend auto operator==( Iter const& a, Iter const& b )
-> bool
{ return a.current_ == b.current_; } // UB if not same sequence.
friend auto operator!=( Iter const& a, Iter const& b )
-> bool
{ return a.current_ != b.current_; }
auto operator*() const
-> int
{ return current_; }
auto operator++()
-> Iter&
{
current_ += p_seq_->delta_;
return *this;
}
auto operator++( int )
-> Iter
{
Iter result{ *this };
current_ += p_seq_->delta_;
return result;
}
};
auto begin() const -> Iter { return Iter{ *this }; }
auto end() const -> Iter { return Iter{ *this, after_ }; }
Sequence( int const first, int const last, bool inclusive = true )
: first_( first )
, after_( last )
, delta_( first <= last? 1 : -1 )
{ if( inclusive ) { after_ += delta_; } }
Sequence( From, int const first, To, int const last )
: Sequence( first, last, true )
{}
Sequence( From, int const first, To_before, int const last )
: Sequence( first, last, false )
{}
};
#include <iostream>
using namespace std;
auto main()
-> int
{
using Seq = Sequence;
for( int const i : Seq{ from, 10, to, 15 } ) { cout << i << ' '; }
cout << endl;
for( int const i : Seq{ from, 15, to, 10 } ) { cout << i << ' '; }
cout << endl;
cout << endl;
for( int const i : Seq{ from, 10, to_before, 15 } ) { cout << i << ' '; }
cout << endl;
for( int const i : Seq{ from, 15, to_before, 10 } ) { cout << i << ' '; }
cout << endl;
}
I'm writing an UTF-8 string class and it's two const and non-const iterator classes. I'm encountering a const problem. Here are the classes :
class Utf8String
{
public:
class ConstIter;
class Iter
{
friend class ConstIter;
private:
Iter();
private:
Utf8String * m_pStr;
utf8::iterator< char * > m_oIter;
public:
Iter( const Iter & );
inline explicit Iter( Utf8String * pStr )
: m_pStr( pStr )
, m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
{ }
inline Iter & operator = ( const Iter & oIter )
{
m_pStr = oIter.m_pStr;
m_oIter = utf8::iterator< char * >(
m_pStr->m_sBuf,
m_pStr->m_sBuf,
m_pStr->m_sBuf + m_pStr->m_nSize );
return *this;
}
inline operator const char * () const
{
return m_oIter.base();
}
inline uchar32_t operator * () const
{
return *m_oIter;
}
inline Iter & operator ++ ()
{
++m_oIter;
return *this;
}
inline Iter & operator -- ()
{
--m_oIter;
return *this;
}
inline bool operator == ( const Iter & oIter )
{
return m_oIter == oIter.m_oIter;
}
inline bool operator != ( const Iter & oIter )
{
return m_oIter != oIter.m_oIter;
}
};
class ConstIter
{
private:
ConstIter();
private:
const Utf8String * m_pStr;
utf8::iterator< const char * > m_oIter;
public:
ConstIter( const ConstIter & );
inline ConstIter( const Iter & oIter )
: m_pStr( oIter.m_pStr )
, m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
{ }
inline ConstIter( const Utf8String * pStr )
: m_pStr( pStr )
, m_oIter( m_pStr->m_sBuf, m_pStr->m_sBuf, m_pStr->m_sBuf + m_pStr->m_nSize )
{ }
inline operator const char * () const
{
return m_oIter.base();
}
inline ConstIter & operator = ( const ConstIter & oIter )
{
m_pStr = oIter.m_pStr;
m_oIter = utf8::iterator< const char * >(
oIter.m_pStr->m_sBuf,
oIter.m_pStr->m_sBuf,
oIter.m_pStr->m_sBuf + oIter.m_pStr->m_nSize );
return *this;
}
inline ConstIter & operator = ( const Iter & oIter )
{
m_pStr = oIter.m_pStr;
m_oIter = utf8::iterator< const char * >(
m_pStr->m_sBuf,
m_pStr->m_sBuf,
m_pStr->m_sBuf + m_pStr->m_nSize );
return *this;
}
inline uchar32_t operator * () const
{
return *m_oIter;
}
inline ConstIter & operator ++ ()
{
++m_oIter;
return *this;
}
inline ConstIter & operator -- ()
{
--m_oIter;
return *this;
}
inline bool operator == ( const ConstIter & oIter )
{
return m_oIter == oIter.m_oIter;
}
inline bool operator != ( const ConstIter & oIter )
{
return m_oIter != oIter.m_oIter;
}
};
// More stuff
};
Which i'm using as follows :
Utf8String sStr = "not const";
for( Utf8String::Iter i = sStr.Begin(); i != sStr.End(); ++i )
{
}
// 2) Iterating over a const UTF-8 string :
const Utf8String sConstStr = "const";
for( Utf8String::ConstIter i = sConstStr.Begin(); i != sConstStr.End(); ++i )
{
}
// 3) Const interators can also iterate over a non-const string :
for( Utf8String::ConstIter i = sStr.Begin(); i != sStr.End(); ++i )
{
}
The problem is that, if the copy constructor of the iterator classes are not declared public, i'm getting the following error, despite that copy constructor not being explicitly used :
Error 1 error C2248: 'core::Utf8String::Iter::Iter' : cannot access private member declared in class 'core::Utf8String::Iter' c:\xxx\main.cpp 20
Declaring these copy constructors public solve the problem.
What happens ? Is the compiler optimizing Utf8String::ConstIter i = sStr.Begin() into Utf8String::ConstIter i( sStr.Begin() ) or doing some other implicit optimization ?
Thanks for your help. :)
EDIT: Using VS2005 and no C++11.
Utf8String::ConstIter i = sStr.Begin(); is a declaration together with an initialization. It is not an assignment. This initialization is done using the copy constructor.
Background
Large application with a bundle of code, I can't change the storage mechanism.
I would like to create an iterator over a set of multi-dimensional data stored in parallel arrays so we can start using std algorithms & containers.
Any ideas on how to make this work correctly?
#include <boost/iterator/iterator_facade.hpp>
#include <iostream>
#include <algorithm>
class curve_point_iterator;
const int curve_size = 10;
class curve
{
public:
curve()
{
std::fill( x, &x[curve_size], 0.0 );
std::fill( y, &y[curve_size], 0.0 );
}
double x[curve_size];
double y[curve_size];
curve_point_iterator begin();
curve_point_iterator end();
};
class point_reference
{
public:
point_reference( double& x_, double& y_ )
: x( x_ )
, y( y_ )
{
}
point_reference& operator = ( point_reference& other )
{
x = other.x;
y = other.y;
return *this;
}
double & x;
double & y;
};
class curve_point_iterator
: public boost::iterator_facade<
curve_point_iterator
, point_reference
, boost::random_access_traversal_tag >
{
public:
curve_point_iterator()
: index(0)
, curve_(nullptr)
{}
explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
: index( index_ )
, curve_( curve_in )
{}
private:
friend class boost::iterator_core_access;
void increment()
{
++index;
}
void decrement()
{
--index;
}
void advance( size_t n )
{
index += n;
}
difference_type distance_to( curve_point_iterator const& other ) const
{
return other.index - this->index;
}
bool equal(curve_point_iterator const& other) const
{
return this->index == other.index && this->curve_ == other.curve_;
}
point_reference& dereference() const
{
auto pt_ref = new( point_reference_buffer ) point_reference( curve_->x[index]
, curve_->y[index] );
return *pt_ref;
}
size_t index;
mutable char point_reference_buffer[sizeof(point_reference)];
curve* curve_;
};
curve_point_iterator curve::begin()
{
return curve_point_iterator( this );
}
curve_point_iterator curve::end()
{
return curve_point_iterator( this, curve_size+1 );
}
int main(int argc, char* argv[])
{
curve crv;
crv.x[1] = 20;
crv.x[2] = 10;
std::sort( crv.begin(), crv.end(), []( point_reference const& a, point_reference const& b )
{
return a.x < b.x;
});
for( auto i = 0; i < curve_size; ++i )
{
std::cout << crv.x[i] << std::endl;
}
return 0;
}
Output
0
20
20
20
20
20
20
20
20
20
After changing to
class point_reference
{
... ( all the other stuff )
double x; // no longer reference
double y; // no longer reference
};
Output
0
20
10
0
0
0
0
0
0
Okay, what you need to do is to introduce a point type (which has value semantics) in addition to point_reference, which has the reference semantics you're looking for. You need the value semantics so that operations such as swap act as the standard expects. You can use the fourth argument of iterator_facade to allow this. Also, this way there is no need to use that mutable buffer, since the point_reference itself is returned by value.
Also, your curve::end() used the wrong index, and should use curve_size as its index.
#include <boost/iterator/iterator_facade.hpp>
#include <iostream>
#include <algorithm>
class curve_point_iterator;
const int curve_size = 10;
class curve
{
public:
curve()
{
std::fill( x, &x[curve_size], 0.0 );
std::fill( y, &y[curve_size], 0.0 );
}
double x[curve_size];
double y[curve_size];
curve_point_iterator begin();
curve_point_iterator end();
};
class point
{
public:
point( const double& x_, const double& y_ )
: x( x_ )
, y( y_ )
{
}
double x;
double y;
};
class point_reference
{
public:
point_reference( double& x_, double& y_ )
: x( x_ ),
y( y_ )
{
}
point_reference& operator = ( const point& other )
{
x = other.x;
y = other.y;
return *this;
}
operator point() const
{
return point(x, y);
}
double & x;
double & y;
point_reference& operator=(const point_reference& other)
{
x = other.x;
y = other.y;
}
point_reference* operator->()
{
return this;
}
point_reference* operator->() const
{
return this;
}
};
class curve_point_iterator
: public boost::iterator_facade<
curve_point_iterator
, point
, boost::random_access_traversal_tag
, point_reference>
{
public:
curve_point_iterator()
: index(0)
, curve_(nullptr)
{}
explicit curve_point_iterator( curve* curve_in, size_t index_ = 0 )
: index( index_ )
, curve_( curve_in )
{}
point_reference operator->() const
{
return dereference();
}
private:
friend class boost::iterator_core_access;
void increment()
{
++index;
}
void decrement()
{
--index;
}
void advance( size_t n )
{
index += n;
}
difference_type distance_to( curve_point_iterator const& other ) const
{
return other.index - this->index;
}
bool equal(curve_point_iterator const& other) const
{
return this->index == other.index && this->curve_ == other.curve_;
}
point_reference dereference() const
{
// auto pt_ref = new( point_reference_buffer ) point_reference( curve_->x[index]
// , curve_->y[index] );
// return *pt_ref;
return point_reference(curve_->x[index], curve_->y[index]);
}
size_t index;
curve* curve_;
};
curve_point_iterator curve::begin()
{
return curve_point_iterator( this );
}
curve_point_iterator curve::end()
{
return curve_point_iterator( this, curve_size );
}
int main(int argc, char* argv[])
{
curve crv;
crv.x[1] = 20;
crv.x[2] = 10;
std::sort( crv.begin(), crv.end(), []( point const& a, point const& b )
{
return a.x < b.x;
});
for( auto i = 0; i < curve_size; ++i )
{
std::cout << crv.x[i] << std::endl;
}
return 0;
}
Output:
0
0
0
0
0
0
0
0
10
20