for my data structures class, we are making a data structure that we can use to easily store and organize data. I am having an issue with the output function of my tree. The error message that I get is:
AccountDB.cpp: In member function ‘void AccountDB::output(std::ostream&) const’:
AccountDB.cpp:23:21: error: passing ‘const AccountDB’ as ‘this’ argument of ‘void
AccountDB::output(std::ostream&, const AccountDB::Elem*)’ discards qualifiers [-fpermissive]
I've been looking around and my output code looks pretty similar to what other people have done. I have no idea, and I don't really understand what the error is trying to tell.
Thanks for your help.
Header:
#ifndef ACCOUNTDB_H
#define ACCOUNTDB_H
#include <iostream>
using namespace std;
#include "AccountRecord.h"
class AccountDB {
public:
AccountDB();
~AccountDB();
void insert( const AccountRecord &v );
AccountRecord * get( const AccountRecord &v );
void output( ostream &s ) const;
private:
struct Elem {
AccountRecord info;
Elem *left;
Elem *right;
};
Elem *root;
void insert( const AccountRecord &v, Elem *&e );
AccountRecord * get( const AccountRecord &v, Elem *&e );
void output( ostream &s, const Elem *e );
};
ostream &operator << ( ostream &s, const AccountDB &v );
#endif
Source
#include "AccountDB.h"
//default constructor
AccountDB::AccountDB() {
root = 0;
}
//destructor
AccountDB::~AccountDB() {
}
//public
void AccountDB::insert( const AccountRecord &v ) {
return insert( v, root );
}
AccountRecord * AccountDB::get( const AccountRecord &v ) {
return get( v, root );
}
void AccountDB::output( ostream &s ) const {
output( s, root );
}
//private
void AccountDB::insert( const AccountRecord &v, Elem *&e ) {
if( e == NULL ) {
e = new Elem();
e->info = v;
}
else if( v < e->info )
insert( v, e->left );
else if( v > e->info )
insert( v, e->right );
}
AccountRecord * AccountDB::get( const AccountRecord &v, Elem *&e ){
if( e->info == v )
return &(e->info);
else if( v < e->info && e->left != NULL )
get( v, e->left );
else if( v > e->info && e->right != NULL )
get( v, e-> right );
else
return NULL;
}
void AccountDB::output( ostream &s, const Elem *e ) {
if( e != NULL ) {
output( s, e->left );
s << e->info << endl;
output( s, e->right );
}
}
ostream &operator << ( ostream &s, const AccountDB &v ) {
v.output( s );
return s;
}
Your output function is not declared const, so when you call
output( s, root );
the compiler tells you that you are calling a non-const function from inside a const function.
There are several ways to deal with this - one is to make output const; the other is to make output static (if you can).
The error is that
void AccountDB::output( ostream &s, const Elem *e )
is not declared as const, but you call it from a const method.
Change the declaration (and definition) to:
void output( ostream &s, const Elem *e ) const;
You can do this since you're not modifying any members inside the function.
Related
with the given code, How do i call insert from main?
I tried, but I always got error :expected primary-expression before.
what is the primary-expression exactly?
Object & front( )
{ return *begin( ); }
const Object & front( ) const
{ return *begin( ); }
Object & back( )
{ return *--end( ); }
const Object & back( ) const
{ return *--end( ); }
void push_front( const Object & x )
{ insert( begin( ), x ); }
void push_back( const Object & x )
{ insert( end( ), x ); }
void pop_front( )
{ erase( begin( ) ); }
void pop_back( )
{ erase( --end( ) ); }
// Insert x before itr.
iterator insert( iterator itr, const Object & x )
{
Node *p = itr.current;
theSize++;
return iterator( p->prev = p->prev->next = new Node( x, p->prev, p ) );
}
To call a function from main:
void My_Function()
{
std::cout << "My_Function\n"
}
int main()
{
My_Function();
return 0;
}
To call an object's method from main:
class Object
{
public:
void print() { std::cout << "Object\n";}
};
int main()
{
Object o;
o.print();
return 0;
}
You should be able to find these examples in some good C++ textbooks.
Edit 1: Static Object functions
You could also declare a method as static inside an object:
class Object_With_Static
{
public:
static void Print_Name()
{
std::cout << "Object_With_Static\n";
};
};
int main()
{
Object_With_Static::Print_Name();
return 0;
}
I have mutually recursive variant types: Value, Array, and Object. The crux of the matter is that I can assign one of the variant types to a Value when it is nested within an Array or Object, which can both contain Value. I cannot assign directly to a Value. The main() function code at the bottom should make this clear. The compiler (GNU GCC 7.2) gives me errors like:
error: conversion from 'JSON::Integer {aka long unsigned int}' to non-scalar type 'JSON::Value' requested
Value v = Integer( 7 );
and oddly does not provide any additional information about assignment operator candidates or anything else. Further, it isn't clear to me how assignment operators I have defined in Value are affecting this problem. Complete working example code follows. Any assignment of one of the variant types directly to a Value type in main() causes a compiler error just like the one above for the Integer type.
Thanks in advance!
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
Value & operator=( String const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Integer const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Object const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Array const & rhs ) {
data = rhs;
return *this;
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef TYPES_HPP
#define TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?"; // compiles fin
o["stuff"] = "yeah!"; // compiles fine
o["inttest"] = Integer( 44 ); // compiles fine
Array a;
a[2] = "yo"; // compiles fine
a[3] = Integer( 6 ); // compiles fine
o["arrtest"] = a;
// Value v = a; // fails to compile
Value v = Integer( 7 ); // fails to compile
std::cout << v;
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}
This was a bad question with an embarrassing oversight. As the commenter pointed out, the problematic lines in main() were initializations rather than assignments. Providing the appropriate constructors solved the problem. For completeness, corrected code follows. It compiles and works fine under GNU GCC 7.2.
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value const & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
template <typename T> Value( T const & rhs ) : data( rhs ) {}
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef JSON_TYPES_HPP
#define JSON_TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?";
o["stuff"] = "yeah!";
o["inttest"] = Integer( 44 );
Array a;
a[2] = "yo";
a[3] = Integer( 6 );
o["arrtest"] = a;
// Value v = a;
Value v = Integer( 7 );
std::cout << v << "\n";
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}
My team designed a library meant to store data from different "signals". A signal is a list of timestamped float values. We have three way to store a signal (depending of the way it was recorded from the hardware in the first place):
MarkerSignal: We store a sorted std::vector of std::pair of (boost::posix_time::ptime,float)
RawSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration) and finally a std::vector of float (each value's timestamp is start time + period * value's index in the vector)
NumericalSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration), a scale (float), an offset (float) and finally a std::vector of short (timestamp is computed as for RawSignal and float value is short*scale+offset)
Those three signals have a common parent class (SignalBase) storing the signal's name, description, unit and stuff like that. We use the visitor pattern to let people nicely "cast" the SignalBase to a MarkerSignal/RawSignal/NumericalSignal and then access the data it contains.
In the end, what we need for each class is to iterate through all elements, one element being actually a pair of (boost::posix_time::ptime,float) (like MarkerSignal). And it's a pain having to create a visitor every time we want to do that.
Storing all signals as a std::vector<std::pair<boost::posix_time::ptime,float>> (or returning an object of this kind on demand) uses too much memory.
We thought the best was probably to define our own iterator object. The iterator would give access to the timestamp and value, like that:
SignalBase* signal = <any signal>;
for ( SignalBase::iterator iter = signal->begin();
iter != signal->end();
++iter )
{
boost::posix_time::ptime timestamp = iter.time();
float value = iter.value();
}
What's the best approach/strategy to create such an iterator class? (simple class with a size_t index attribute, or a MarkerSignal/RawSignal/NumericalSignal container's specific iterator as attribute, store a std::pair<boost::posix_time::ptime,float> and update it from a ++ operator...).
Also, I would much prefer if the solution rpoposed avoids using a virtual table (to have ++, time(), and value() be faster when iterating on huge signals).
To sum up I think the best you can achieve if you value for efficiency could be something like this:
template <typename SignalType, typename Functor = function<void(typename SignalType::value_type&&) > >
void iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
Then for call:
iterateThroughSignal<MarkerSignal>(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
I'm not sure if you are using C++11 so the lambda can be replace by function pointer, rvalue reference using lvalue reference and the std::function with a function signature...
Edit:
To make it compile when the type of the foo signature won't match the SignalType::value_type there will be a need of playing a little bit with sfinae:
template <typename SignalType>
class IterateHelper {
template <typename Functor>
static typename enable_if<first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
template <typename Functor>
static typename enable_if<!first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
}
};
I leave the implementation of first_param_is helper struct to you... Call would change to:
IteratorHelper<MarkerSignal>::iterateThroughSignal(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
As I wanted something easy to use for people using my library (be able to esily do a for loop) I finally implemented my own iterator like that:
Added two virtual functions in SignalBase (found no alternative to that, runtime will use the virtual table):
virtual size_t floatDataCount() const = 0;
virtual bool loadFloatInfoAt( size_t pos, SignalFloatIter::ValueInfo& info ) const = 0;
Added functions in SignalBase to get begin/end iterators:
inline BDL::SignalFloatIter beginFloatIter() const { return BDL::SignalFloatIter::beginIter( *this ); }
inline BDL::SignalFloatIter endFloatIter() const { return BDL::SignalFloatIter::endIter( *this ); }
Declared iterator class like that:
class SignalFloatIter
{
public:
SignalFloatIter( const SignalBase* signal = NULL, size_t pos = 0 );
SignalFloatIter( const SignalFloatIter& iter );
static SignalFloatIter beginIter( const SignalBase& signal );
static SignalFloatIter endIter( const SignalBase& signal );
SignalFloatIter& operator=( const SignalFloatIter& iter );
bool operator==( const SignalFloatIter& iter ) const;
bool operator!=( const SignalFloatIter& iter ) const;
/** Pre-increment operator */
SignalFloatIter& operator++();
/** Post-increment operator */
SignalFloatIter operator++(int unused);
inline const BDL::time& when() const { assert( m_valid ); return m_info.first.first; }
inline const BDL::duration& duration() const { assert( m_valid ); return m_info.first.second; }
inline const float& value() const { assert( m_valid ); return m_info.second; }
inline size_t index() const { assert( m_valid ); return m_pos; }
inline BDL::MarkerKey markerKey() const { assert( m_valid ); return std::make_pair( when(), duration() ); }
inline bool valid() const { return m_valid; }
typedef std::pair<BDL::time,BDL::duration> TimeInfo;
typedef std::pair<TimeInfo,float> ValueInfo;
private:
const SignalBase* m_signal;
size_t m_pos;
bool m_valid;
ValueInfo m_info;
void loadCurInfo();
};
Implemented:
SignalFloatIter::SignalFloatIter( const SignalBase* signal, size_t pos ) :
m_signal( signal ),
m_pos( pos )
{
loadCurInfo();
}
SignalFloatIter::SignalFloatIter( const SignalFloatIter& iter )
{
operator=( iter );
}
SignalFloatIter SignalFloatIter::beginIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, 0 );
}
SignalFloatIter SignalFloatIter::endIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, signal.floatDataCount() );
}
SignalFloatIter& SignalFloatIter::operator=( const SignalFloatIter& iter )
{
if ( this != &iter )
{
m_signal = iter.m_signal;
m_pos = iter.m_pos;
m_info = iter.m_info;
m_valid = iter.m_valid;
}
return *this;
}
bool SignalFloatIter::operator==( const SignalFloatIter& iter ) const
{
if ( m_signal == iter.m_signal )
{
if ( m_pos == iter.m_pos )
{
assert( m_valid == iter.m_valid );
if ( m_valid )
assert( m_info == iter.m_info );
return true;
}
else
{
return false;
}
}
else
{
assert( false );
return false;
}
}
bool SignalFloatIter::operator!=( const SignalFloatIter& iter ) const
{
return !( *this == iter );
}
SignalFloatIter& SignalFloatIter::operator++()
{
++m_pos;
loadCurInfo();
return *this;
}
SignalFloatIter SignalFloatIter::operator++( int unused )
{
SignalFloatIter old = *this;
assert( unused == 0 ); // see http://en.cppreference.com/w/cpp/language/operator_incdec
++m_pos;
loadCurInfo();
return old;
}
void SignalFloatIter::loadCurInfo()
{
if ( m_signal )
{
m_valid = m_signal->loadFloatInfoAt( m_pos, m_info );
}
else
{
assert( false );
m_valid = false;
}
}
It's pretty straightforward and easy to use for any signal:
std::cout << "Signal timestamped data are: ";
for ( BDL::SignalFloatIter iter = signal.beginFloatIter();
iter != signal.endFloatIter();
++iter )
{
std::cout << iter.when() << " : " << iter.value() << std::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.
I am working on one of my classes and I have come upon a stumbling block. I'll give you a sample of my source only the names of classes, methods and variable names are different, but the implementation is the same. You will see my problem/s, question/s & concern/s within the code block to the appropriate function.
MyClass.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
const std::string strOne = std::string( "one" );
const std::string strTwo = std::string( "two" );
const std::string strThree = std::string( "three" );
const std::string strUnknown = std::string( "unknown" );
enum Count {
ONE,
TWO,
THREE,
UNKNOWN
};
class MyClass {
private:
const std::map<Count, const std::string> m_mCount = createCountMap();
unsigned short m_uCount;
std::vector<std::string> m_vItems;
std::multimap<const std::string, const std::string> m_mmAssociatedItems;
public:
MyClass();
MyClass( const std::string strItem1, const std::string strItem2 );
static MyClass* get();
void addItem( Count type, const std::string& strItem2 );
void addItem( const std::string& strItem1, const std::string& strItem2 );
private:
static const std::map<Count, const std::string> createCountMap();
};
#endif // MY_CLASS_H
MyClass.cpp
#include "stdafx.h"
#include "MyClass.h"
static MyClass* s_pMyClass = nullptr;
const std::map<Count, const std::string> MyClass:createCountMap() {
std::map<Count, const std::string> m;
m.insert( std::make_pair( Count::ONE, strOne ) );
m.insert( std::make_pair( Count::TWO, strTwo ) );
m.insert( std::make_pair( Count::Three, strThree ) );
m.insert( std::make_pair( Count::UNKNOWN, strUnknown ) );
return m;
} // createCountMap
MyClass* MyClass::get() {
if ( !s_pMyClass ) {
return nullptr;
}
return s_pMyClass;
} // get
MyClass::MyClass() : m_uCount( 0 ) {
m_vItems.clear();
m_mmAssociatedItems.clear();
} // MyClass
MyClass::MyClass( const std::string& strItem1, const std::string& strItem2 ) :
m_uCount( 0 ) {
addItem( strItem1, strItem2 );
} // MyClass
void MyClass::addItem( Count type, const std::string& strItem2 ) {
const std::map<Count, const std::string>::const_iterator it = m_mCount.find( type );
if ( it == m_mCount.end() ) {
// Did not find a valid item key!
// Throw Exception Here!
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( it->second, m_vItems.at( m_uCount ) ) );
++m_uCount;
}
void MyClass::addItem( const std::string& strItem1, const std::string& strItem2 ) {
// I need to do a similar thing as above instead of looking through my
// const std::map at the key values for a match, with this overloaded
// function call I need to use strItem1 as the search item to see if it
// is within the contents of this map which would be the map's ->second
// value. If not throw a similar error as above otherwise once it is
// found populate my vector and multimap same as above and increment
// my count variable.
// This would logically be my next step
const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
// It Is Within This For Loop That It Fails To Compile! It
// Fails At The it++ Part! Is There A Way Around This? Or
// Am I Missing Something Simple?
for ( ; it != m_mCount.end(); it++ ) {
// If strItem1 == it->second && it != m_mCount.end()
// found it, add items, if not throw error
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( strItem1, strItem2 ) );
++m_uCount;
}
In my source, it is this second function which is more important then the first! Any Help or suggestions is very much appreciated.
const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
The first const should be removed. Otherwise it cannot be moved forward, and you cannot iterate through m_mCount.