mlimber said:
Can you post a complete code sample that demonstrates the problem?
Well, in fact I can. This is so shrunk. Still 200 lines...
The thing I'm asking is of course at end of code.
Before that: namespace detail
const_traits, nonconst_traits -- iterator traits
ref_proxy -- the problem child
micromap_iter is real code, the point of it is operator*()
- it wants to return a proper pair<const Key, T>, but key, T
are stored separately so it returns a ref_proxy<const Key, T>
which almost resolves to pair<const Key &, T&>
The micromap<Key, T> class is a joke, but shows the basic behaviour:
key, T's are stored separately, it has a mm_iter_base iterator
that offers methods key(), val() and no dereference.
The micromap::iterator typedef is real code - I ripped it off
various implementations to get proper syntax and semantix.
Bonus question: Is the whole iterator definition rightish?
(given that operator--(), operator++(int) etc are not defined,
so it's incomplete, but those details are not relevant
in this example).
The problem is shown in fiddle_my_map at end of post:
iterator dereference returns a ref_proxy object, which
(i) converts to pair<const Key, T>,
(iia) can be assigned to a ref_proxy &
(iib) the reference to a ref_proxy is mutable,
ie ref.second = 5 compiles, and will change the map,
BUT
(iii) (*it).second gives compiler error "not an l-value". (MSVC 7.1)
I want (*it).second to be assignable. What am I missing?
-------- 8< -----------------------
#include <utility>
#include <iterator>
int main(int argc, char* argv[])
{
void fiddle_my_map();
fiddle_my_map();
return 0;
}
namespace detail {
template <class T> struct nonconst_traits;
template <class T>
struct const_traits {
typedef T value_type;
typedef const T& reference;
typedef const T* pointer;
typedef const_traits<T> ConstTraits;
typedef nonconst_traits<T> NonConstTraits;
};
template <class T>
struct nonconst_traits {
typedef T value_type;
typedef T& reference;
typedef T* pointer;
typedef const_traits<T> ConstTraits;
typedef nonconst_traits<T> NonConstTraits;
};
// This attempts to fake std:

air<const Key, T> by reference to T
template<class KeyT, class DataT>
struct ref_proxy
{
typedef const KeyT first_type;
typedef DataT second_type;
//! Pair Associative value_type
typedef std:

air<const KeyT, DataT> pair_type;
ref_proxy(first_type& a, second_type& b) : first(a), second(b) {}
//! Copy convertible to Pair Associative value_type
operator pair_type() const { return pair_type(first, second); }
first_type & first;
second_type & second;
};
template<class BaseIterT, class TraitsT>
struct micromap_iter
{
typedef typename TraitsT::ConstTraits ConstTraits;
typedef typename TraitsT::NonConstTraits NonConstTraits;
typedef BaseIterT base_iter;
typedef micromap_iter<BaseIterT, TraitsT> this_type;
typedef typename TraitsT::value_type value_type;
typedef typename TraitsT:

ointer pointer;
typedef typename TraitsT::reference reference;
typedef std::bidirectional_iterator_tag iterator_category;
typedef ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef micromap_iter<BaseIterT, ConstTraits> const_iterator;
typedef micromap_iter<BaseIterT, NonConstTraits> iterator;
friend const_iterator;
friend iterator;
micromap_iter() {}
// copy constructor for iterator and constructor from iterator for const_iterator
micromap_iter(const iterator& it) : m_iter(it.m_iter) {}
micromap_iter(base_iter it) : m_iter(it) {}
value_type operator*() const {
return value_type(const_cast<base_iter&>(m_iter).key(), const_cast<base_iter&>(m_iter).val());
}
this_type& operator++() { m_iter.increment(); return *this; }
this_type& operator--() { m_iter.decrement(); return *this; }
bool operator== (const_iterator rhs) const { return m_iter.pos() == rhs.m_iter.pos(); }
bool operator!= (const_iterator rhs) const { return m_iter.pos() != rhs.m_iter.pos(); }
private:
base_iter m_iter;
};
}
template<class KeyT, class DataT>
class micromap
{
public:
typedef KeyT key_type;
typedef DataT mapped_type;
typedef std:

air<const KeyT, DataT> value_type;
typedef value_type * pointer;
typedef const value_type * const_pointer;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef std::size_t size_type;
typedef detail::ref_proxy<KeyT, DataT> ref_proxy;
struct mm_iter_base;
micromap() : m_count(0) {}
typedef detail::micromap_iter< mm_iter_base,
detail::nonconst_traits<ref_proxy>
> iterator;
typedef detail::micromap_iter< mm_iter_base,
detail::const_traits<ref_proxy>
> const_iterator;
iterator begin() { return mm_iter_base(keys, vals, 0); }
const_iterator begin() const { return mm_iter_base(keys, vals, 0); }
iterator end() { return mm_iter_base(keys, vals, m_count); }
const_iterator end() const { return mm_iter_base(keys, vals, m_count); }
// iterator implementation
struct mm_iter_base
{
typedef mm_iter_base this_type;
mm_iter_base(key_type* ks, mapped_type* ms, size_type index)
: keys(ks), vals(ms), m_index(index)
{}
mm_iter_base() : keys(0), vals(0), m_index(-1) {}
const key_type& key() const { return keys[m_index]; }
mapped_type& val() { return vals[m_index]; }
mapped_type val() const { return vals[m_index]; }
void increment() { ++m_index; }
void decrement() { --m_index; }
size_t pos() const { return m_index; }
private:
size_type m_index;
key_type* keys;
mapped_type* vals;
};
// ok, rest of this class is bad joke, but I don't want to post 2000 lines
mapped_type& operator[](const key_type& k)
{
// strong exception guarantee

if (m_count >= 3)
throw std::bad_alloc("micromap full");
size_type index = 0;
while( index < m_count && k > keys[index] )
index++;
// sorted multiple...
if (index < m_count) {
std::copy(keys + index, keys + m_count, keys + index + 1);
std::copy(vals + index, vals + m_count, vals + index + 1);
vals[index] = mapped_type();
}
keys[index] = k;
m_count++;
return vals[index];
}
private:
size_type m_count;
key_type keys[3];
mapped_type vals[3];
};
void fiddle_my_map()
{
typedef micromap<std::string, int> MyMap;
MyMap mymap;
mymap["gack"] = 3;
MyMap::iterator it = mymap.begin();
typedef detail::ref_proxy<std::string, int> proxy;
proxy& ref = *it;
ref.second = 5;
// ref_proxy is convertible to pair<key,T>
MyMap::value_type seeme = *it;
// BUT assignment to dereferenced ref_proxy doesn't work
(*it).second = 5; // compiler error "must be l-value". WHY!!?? (*sob*)
mymap["and..."] = 3;
// This prints and...=3 gack=5
while (it != mymap.end()) {
std::cout << (*it).first << "=" << (*it).second << " ";
++it;
}
}