473,654 Members | 3,114 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

reference l-value

Hi,

I'm (still) trying to return a pair<const Key, T> from
iterator dereference. So I defined a proxy class in the
obvious way:

template<class KeyT, class DataT>
struct ref_proxy
{
typedef const KeyT first_type;
typedef DataT second_type;
//! Pair Associative value_type
typedef std::pair<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;
};

It is passed into iterator class via nonconst_traits <ref_proxy<Key, T> >,
and typedef'd as value_type in there.
Now try to use it, with mixed failure:

mymap::MyMap<st d::string, int> mappy;
mappy["gack"] = 3;
MyMap::iterator it = mappy.begin();

(*it).second = 5; // compiler error: not an l-value

// but this works, and does the right thing
typedef mymap::detail:: ref_proxy<std:: string, int> proxy;
proxy& ref = *it;
ref.second = 5;
What gives? I read about references and noted non-const refs
get no type conversion. Is it a type lookup failure, or what
am I missing?

Thanks,

homsan

Dec 20 '05 #1
5 2761
homsan toft wrote:
Hi,

I'm (still) trying to return a pair<const Key, T> from
iterator dereference. So I defined a proxy class in the
obvious way:

template<class KeyT, class DataT>
struct ref_proxy
{
typedef const KeyT first_type;
typedef DataT second_type;
//! Pair Associative value_type
typedef std::pair<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;
};

It is passed into iterator class via nonconst_traits <ref_proxy<Key, T> >,
and typedef'd as value_type in there.
Now try to use it, with mixed failure:

mymap::MyMap<st d::string, int> mappy;
mappy["gack"] = 3;
MyMap::iterator it = mappy.begin();

(*it).second = 5; // compiler error: not an l-value

// but this works, and does the right thing
typedef mymap::detail:: ref_proxy<std:: string, int> proxy;
proxy& ref = *it;
ref.second = 5;
What gives? I read about references and noted non-const refs
get no type conversion. Is it a type lookup failure, or what
am I missing?

Thanks,

homsan


Can you post a complete code sample that demonstrates the problem?

Cheers! --M

Dec 20 '05 #2
mlimber wrote:

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::itera tor 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::pair<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::pair<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::ConstT raits ConstTraits;
typedef typename TraitsT::NonCon stTraits NonConstTraits;

typedef BaseIterT base_iter;
typedef micromap_iter<B aseIterT, TraitsT> this_type;

typedef typename TraitsT::value_ type value_type;
typedef typename TraitsT::pointe r pointer;
typedef typename TraitsT::refere nce reference;

typedef std::bidirectio nal_iterator_ta g iterator_catego ry;
typedef ptrdiff_t difference_type ;
typedef std::size_t size_type;

typedef micromap_iter<B aseIterT, ConstTraits> const_iterator;
typedef micromap_iter<B aseIterT, NonConstTraits> iterator;
friend const_iterator;
friend iterator;

micromap_iter() {}
// copy constructor for iterator and constructor from iterator for const_iterator
micromap_iter(c onst iterator& it) : m_iter(it.m_ite r) {}

micromap_iter(b ase_iter it) : m_iter(it) {}

value_type operator*() const {
return value_type(cons t_cast<base_ite r&>(m_iter).key (), const_cast<base _iter&>(m_iter) .val());
}

this_type& operator++() { m_iter.incremen t(); return *this; }

this_type& operator--() { m_iter.decremen t(); 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::pair<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_pro xy<KeyT, DataT> ref_proxy;

struct mm_iter_base;

micromap() : m_count(0) {}

typedef detail::microma p_iter< mm_iter_base,
detail::noncons t_traits<ref_pr oxy> iterator; typedef detail::microma p_iter< mm_iter_base,
detail::const_t raits<ref_proxy > const_iterator;


iterator begin() { return mm_iter_base(ke ys, vals, 0); }
const_iterator begin() const { return mm_iter_base(ke ys, vals, 0); }
iterator end() { return mm_iter_base(ke ys, vals, m_count); }
const_iterator end() const { return mm_iter_base(ke ys, vals, m_count); }

// iterator implementation
struct mm_iter_base
{
typedef mm_iter_base this_type;

mm_iter_base(ke y_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::s tring, int> MyMap;
MyMap mymap;
mymap["gack"] = 3;
MyMap::iterator it = mymap.begin();
typedef detail::ref_pro xy<std::string, int> proxy;
proxy& ref = *it;
ref.second = 5;
// ref_proxy is convertible to pair<key,T>
MyMap::value_ty pe 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;
}
}

Dec 21 '05 #3
On 2005-12-21, homsan toft <no*****@specif ic.org> wrote:
mlimber wrote:

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::itera tor 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?


There were several errors I had to correct, but I still can't get
the code to compile as far as you say.
-------- 8< -----------------------

#include <utility>
#include <iterator>
Missing headers <iostream> and <exception>

SNIP
// This attempts to fake std::pair<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::pair<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); }
How can that operation be applied to a const ref_proxy?
first_type & first;
second_type & second;
};

template<class BaseIterT, class TraitsT>
struct micromap_iter
{
typedef typename TraitsT::ConstT raits ConstTraits;
typedef typename TraitsT::NonCon stTraits NonConstTraits;

typedef BaseIterT base_iter;
typedef micromap_iter<B aseIterT, TraitsT> this_type;

typedef typename TraitsT::value_ type value_type;
typedef typename TraitsT::pointe r pointer;
typedef typename TraitsT::refere nce reference;

typedef std::bidirectio nal_iterator_ta g iterator_catego ry;
typedef ptrdiff_t difference_type ;
typedef std::size_t size_type;

typedef micromap_iter<B aseIterT, ConstTraits> const_iterator;
typedef micromap_iter<B aseIterT, NonConstTraits> iterator;
friend const_iterator;
friend iterator;
After correcting the syntax error in the friend declarations, g++
3.3.1 refuses to accept those declarations, since the class
becomes "implicitly friends with itself."
micromap_iter() {}
// copy constructor for iterator and constructor from iterator for const_iterator
micromap_iter(c onst iterator& it) : m_iter(it.m_ite r) {}

micromap_iter(b ase_iter it) : m_iter(it) {}

value_type operator*() const {
return value_type(cons t_cast<base_ite r&>(m_iter).key (), const_cast<base _iter&>(m_iter) .val());
}
How can that operation be applied to a const object?
this_type& operator++() { m_iter.incremen t(); return *this; }

this_type& operator--() { m_iter.decremen t(); 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;
};
}

// 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");
SNIP

std::bad_alloc hasn't got a constructor that takes an argument.
void fiddle_my_map()
{
typedef micromap<std::s tring, int> MyMap;
MyMap mymap;
mymap["gack"] = 3;
MyMap::iterator it = mymap.begin();
typedef detail::ref_pro xy<std::string, int> proxy;
proxy& ref = *it;


g++3.3.1 refuses to compile that line. Does the conversion work
on your compiler?

The proliferation of types is quite confusing.

Perhaps it would be simpler to provide instead a key_iterator,
value_iterator and const_value_ite rator?

Another solution might be to do as std::map does: handle the
conversion from std::pair<KeyT, DataT> to std::pair<KeyT const,
DataT> in your insert routine (using temporaries), storing nodes
internally in a std::pair<KeyT const, DataT>. That's got to be
easier than this attempt to contravene the type system using
proxy objects.

--
Neil Cerutti
Dec 21 '05 #4
Neil Cerutti wrote:
On 2005-12-21, homsan toft <no*****@specif ic.org> wrote:

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?

There were several errors I had to correct, but I still can't get
the code to compile as far as you say.


Neil, thanks for your comments!
I'm trying to acquire better habits... apologies for not trying harder.

Running it through Comeau online helps a lot (why didn't think of that sooner??).

Now on max warning level, MSVC does mention that the conversion to ref_proxy&
is nonstandard, Ie, in fiddle_my_map() :
MyMap::iterator it = mymap.begin();
typedef detail::ref_pro xy<std::string, int> proxy;
proxy& ref = *it; //<<<< so now I know this is incorrect conversion

Comeau reports error: "initial value of reference to non-const must be an lvalue"

Moreover, MSVC doesn't accept the conversion
(*it).second = 5; // compiler error "must be l-value".
- but Comeau gulps it.

So MSVC near-silently converts the non-lvalue struct, but chokes on the l-value member(?)
Your other comments duly noted.

(except in proxy_ref struct:
typedef std::pair<const KeyT, DataT> pair_type;

operator pair_type() const { return pair_type(first , second); }


How can that operation be applied to a const ref_proxy?


It returns a copy std::pair<KeyT, DataT>. Is that non-const?

line 9 of fiddle_my_map() ,
// ref_proxy is convertible to pair<key,T>
MyMap::value_ty pe seeme = *it;
causes no complaint from Comeau.)

Perhaps it would be simpler to provide instead a key_iterator,
value_iterator and const_value_ite rator?
I'd like to do as nearly as possible a drop-in replacement for map...
Another solution might be to do as std::map does: handle the
conversion from std::pair<KeyT, DataT> to std::pair<KeyT const,
DataT> in your insert routine (using temporaries), storing nodes
internally in a std::pair<KeyT const, DataT>. That's got to be
easier than this attempt to contravene the type system using
proxy objects.


I'm not deeply in love with the ref_proxy class, just trying to fake
that pair<const K, T> interface.
Did seem like it could be made to work, but guess I'll drop it.
Thanks,

homsan
Dec 22 '05 #5
On 2005-12-22, homsan toft <no*****@specif ic.org> wrote:
Neil Cerutti wrote:
operator pair_type() const { return pair_type(first , second); }
How can that operation be applied to a const ref_proxy?


It returns a copy std::pair<KeyT, DataT>. Is that non-const?

line 9 of fiddle_my_map() ,
// ref_proxy is convertible to pair<key,T>
MyMap::value_ty pe seeme = *it;
causes no complaint from Comeau.)


I did not notice that before. I assumed it was returning a
ref_proxy, which contains modifiable references. If you return a
copy of the data, then nothing you modify in that copy will have
any effect on the data stored in your map.
I'm not deeply in love with the ref_proxy class, just trying to
fake that pair<const K, T> interface. Did seem like it could be
made to work, but guess I'll drop it.


It most likely can be made to work; it just won't be easy. ;-)
I've not been able to come up with anything that doesn't use a
reinterpret_cas t.

--
Neil Cerutti
Dec 22 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
9488
by: Jan Pieter Kunst | last post by:
(apologies if this message is a duplicate -- my news server seems to have problems) Greetings, When using PHP 4, this: // ex. 1 class A { function A(&$obj) {
2
13115
by: RU | last post by:
Hi, I am working on a porting project to port C/C++ application from unixware C++, AT&T Standard components to g++ with STL on Linux. This application has been working properly on Unixware/C++/AT&T componets environment. I have been able to compile all modules after making necessary changes in LINUX/gcc/STL environment. We have two templates defined XList and XMap.
110
9899
by: Mr A | last post by:
Hi! I've been thinking about passing parameteras using references instead of pointers in order to emphasize that the parameter must be an object. Exemple: void func(Objec& object); //object must be an object instead of
4
1531
by: Edward Diener | last post by:
I have a class Y in assembly B which is derived from a class Z in assembly C. So I correctly add a reference to assembly C in assembly B, build assembly B and everything builds fine. Now I create an assembly A which refers to class Y in assembly B. So I add a reference in assembly A to assembly B, and attempt to build. I get an error message, C3264, saying that it could not find the type Z, and that it is in assembly C to which I have no...
22
3487
by: tshad | last post by:
If I am passing a variable by reference to another routine by reference, do I need to dereference first? string testString; .... FirstSub(ref firstString) { HandleString(ref firstString); //do I need to de reference here or just pass theString without the "ref"
27
4206
by: David W | last post by:
I'm almost tearing my hair out. A colleague claimed that a null reference can exist, like this: void f( int& p ) { printf( "%d\n", p ); } int main (int argc, char *argv) {
3
789
by: Michael Sgier | last post by:
Hi i get thousands of messages like below. How shall i resolve that? Thanks Mcihael Release/src/Utility/RawImage.o: In function `CMaskImage::CMaskImage(int, int, char const*)': RawImage.cpp:(.text+0x15dc): undefined reference to `popen(PFS*, char const*)'
10
1624
by: Summercool | last post by:
so many places, including the book PHP in a Nutshell, p. 80, it says: $a =& $b # set $a to reference $b if $a reference $b, then while you can say $b =1, you can't really say $a = 1. you need to say *($a) = 1 as in C or C++. Referencing must be coupled with dereferencing, and PHP is not doing the dereferencing, so why is it call referencing in the first place? (don't tell me PHP automatically dereference... as it will be really...
41
3639
by: Summercool | last post by:
Can we confirm the following? also someone said, Java also has "reference" like in C++, which is an "implicit pointer": Pointer and Reference --------------------- I am starting to see what pointer and reference are and how they relate to each other.
7
5778
by: Johannes Bauer | last post by:
Hello Group, please consider the following code #include <vector> #include <iostream> #define USE_CONST #define USE_STRING
0
8294
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8709
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8494
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8596
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7309
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6162
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4150
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
2719
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
1924
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.