C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Reverse iterators

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
ThosRTanner
Guest





PostPosted: Tue Jul 26, 2005 1:08 pm    Post subject: Reverse iterators Reply with quote



I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator>
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator<wibble::const_iterator>
(*)(wibble::const_iterator);
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though less
helpful), so I presume it is standard.

The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));
return magic_table->magic[idx].valid() ? x : ++x;
}

What is wrong with that code? It works fine if I use a const_iterator
and change the return statement to "return const_reverse_iterator(thing
? x : --x)".

Why can't one increment a const_reverse_iterator under certain
circumstances?

Thanks


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
M Jared Finder
Guest





PostPosted: Tue Jul 26, 2005 6:15 pm    Post subject: Re: Reverse iterators Reply with quote



ThosRTanner wrote:
Quote:
I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator (*)(wibble::const_iterator);
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though less
helpful), so I presume it is standard.

The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));
return magic_table->magic[idx].valid() ? x : ++x;
}

What is wrong with that code? It works fine if I use a const_iterator
and change the return statement to "return const_reverse_iterator(thing
? x : --x)".

Why can't one increment a const_reverse_iterator under certain
circumstances?

This code is an example of "The Most Vexing C++ Parse". You declared a
function named x that takes a const_iterator parameter named idx and
returns a const_reverse_iterator. You wanted to declare a variable
named x of type const_reverse_iterator.

To fix this, you'll need to make the declaration look less like a
function declaration:

// assuming there is an implicit conversion available
const_reverse_iterator x = const_iterator( idx );

-- MJF

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Tue Jul 26, 2005 6:16 pm    Post subject: Re: Reverse iterators Reply with quote



Hi Tom,

As per your warning message, you have declared a function in a
particularly creative way. Specifically...

const_reverse_iterator x(const_iterator(idx));

Declares a function called x that returns a const_reverse_iterator and
takes an argument of type const_iterator named idx. This idx is a
formal parameter name, and nothing to do with your local variable.

Cheers,

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gianluca Silvestri
Guest





PostPosted: Tue Jul 26, 2005 6:17 pm    Post subject: Re: Reverse iterators Reply with quote


"ThosRTanner" <ttanner2 (AT) bloomberg (DOT) net> ha scritto nel messaggio
news:1122380369.828417.172100 (AT) o13g2000cwo (DOT) googlegroups.com...
Quote:
I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator (*)(wibble::const_iterator);
If you read it carefully you can see the answer: the type g++ points to is

pointer to function !
Quote:
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though less
helpful), so I presume it is standard.

The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));

Here you declare a function named x that takes a parameter named idx of type
const_iterator and returns a value a const_reverse_iterator type



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ben Hutchings
Guest





PostPosted: Tue Jul 26, 2005 11:10 pm    Post subject: Re: Reverse iterators Reply with quote

ThosRTanner <ttanner2 (AT) bloomberg (DOT) net> wrote:
Quote:
I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator (*)(wibble::const_iterator);
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though less
helpful), so I presume it is standard.

Perhaps you should read the error message more carefully. It's
referring to a *function pointer* type, which of course you cannot
perform pointer arithmetic with.

Quote:
The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));
snip


This declares x as a function pointer (of the type specified in the
error message). idx is used as the (irrelevant) parameter name.
You could use:
const_reverse_iterator x((const_iterator(idx)));
to avoid this.

--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
ThosRTanner
Guest





PostPosted: Wed Jul 27, 2005 3:32 pm    Post subject: Re: Reverse iterators Reply with quote



Ben Hutchings wrote:
Quote:
ThosRTanner <ttanner2 (AT) bloomberg (DOT) net> wrote:
I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator (*)(wibble::const_iterator);
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though less
helpful), so I presume it is standard.

Perhaps you should read the error message more carefully. It's
referring to a *function pointer* type, which of course you cannot
perform pointer arithmetic with.
Well, from other compilers I got something like "expect lvalue for ++"

- none of the rest of the helpful stuff. And I didn't think I had
declared a function pointer, so I was sort of confused by the (*).

Quote:
The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));
snip

This declares x as a function pointer (of the type specified in the
error message). idx is used as the (irrelevant) parameter name.
You could use:
const_reverse_iterator x((const_iterator(idx)));
to avoid this.

Something is being done here that I dont understand. I thought
parameters had to have types, as in
const_reverse_iterator x(const_iterator idx);

Or could I declare all functions in this way, for instance replacing
int wibble(int a, float b)
with
int wibble(int(a), float(b))

Under the circumstances, that's probably not a helpful addition to the
language :-(


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Jul 28, 2005 11:13 am    Post subject: Re: Reverse iterators Reply with quote

ThosRTanner wrote:
Quote:
Ben Hutchings wrote:
ThosRTanner <ttanner2 (AT) bloomberg (DOT) net> wrote:
I've just got a very strange message out of gcc:

in member function std::reverse_iterator<wibble::const_iterator
wibble::rbegin() const
error: iso c++ forbids incrementing a pointer of type
'std::reverse_iterator (*)(wibble::const_iterator);
error: invalid lvalue in increment.

Other compilers give errors on the same statement (though
less helpful), so I presume it is standard.

Perhaps you should read the error message more carefully.
It's referring to a *function pointer* type, which of course
you cannot perform pointer arithmetic with.

Well, from other compilers I got something like "expect lvalue
for ++" - none of the rest of the helpful stuff. And I didn't
think I had declared a function pointer, so I was sort of
confused by the (*).

Well, a function isn't an lvalue, so the error message was
correct.

Quote:
The code in question is something along the lines of

const_reverse_iterator rbegin() const
{
int idx = magic_table->right_end;
const_reverse_iterator x(const_iterator(idx));
snip

This declares x as a function pointer (of the type specified
in the error message). idx is used as the (irrelevant)
parameter name. You could use:
const_reverse_iterator x((const_iterator(idx)));
to avoid this.

Something is being done here that I dont understand. I thought
parameters had to have types, as in
const_reverse_iterator x(const_iterator idx);

So. That's pretty much the same thing as you had initially
written.

Quote:
Or could I declare all functions in this way, for instance
replacing
int wibble(int a, float b)
with
int wibble(int(a), float(b))

Obviously.

Quote:
Under the circumstances, that's probably not a helpful
addition to the language Sad

It's not an addition. It's not for nothing that we speak of
"type expressions" -- type declarations in C++ (and in C) have
an expression like syntax. And it's perfectly normal that you
can put any expression in parentheses without modifying its
meaning.

Note that the expression syntax needs the parentheses for things
like:
void f( int (*pf)() ) ;

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
ThosRTanner
Guest





PostPosted: Fri Jul 29, 2005 9:49 am    Post subject: Re: Reverse iterators Reply with quote


[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
Something is being done here that I dont understand. I thought
parameters had to have types, as in
const_reverse_iterator x(const_iterator idx);

So. That's pretty much the same thing as you had initially
written.
Only on the basis that you can do the replacement just below.


Quote:
Or could I declare all functions in this way, for instance
replacing
int wibble(int a, float b)
with
int wibble(int(a), float(b))

Obviously.
If it was /that/ obvious, there wouldn't be a special name for this

problem!

Quote:
Under the circumstances, that's probably not a helpful
addition to the language :-(

It's not an addition. It's not for nothing that we speak of
"type expressions" -- type declarations in C++ (and in C) have
an expression like syntax. And it's perfectly normal that you
can put any expression in parentheses without modifying its
meaning.
But the fix for this is to put the expression in parentheses. So

clearly leaving out parentheses round an expression modifies its
meaning. And putting () round something can change it from
not-an-expression to an expression. That isn't what you really expect
parentheses to do.

Quote:
Note that the expression syntax needs the parentheses for things
like:
void f( int (*pf)() ) ;
Sure, but that is a function prototype, not a plain type (so to speak).


On the whole, I consider raw function prototypes as function parameters
as bad coding style. That is just about OK, but anything more complex
than that gets fairly rapidly unreadable (I've seen something with 2
function pointers, each with about 3 parameters, one of which expected
a function pointer passed to it).


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Jul 29, 2005 1:48 pm    Post subject: Re: Reverse iterators Reply with quote

ThosRTanner wrote:
Quote:
kanze (AT) gabi-soft (DOT) fr wrote:
Something is being done here that I dont understand. I
thought parameters had to have types, as in

const_reverse_iterator x(const_iterator idx);

So. That's pretty much the same thing as you had initially
written.

Only on the basis that you can do the replacement just below.

Or could I declare all functions in this way, for instance
replacing
int wibble(int a, float b)
with
int wibble(int(a), float(b))

Obviously.

If it was /that/ obvious, there wouldn't be a special name for
this problem!

It's obvious, given both versions, and asked the question, that
the second version is both legal, and equivalent to the first.

If you're goal is to write a data declaration with
initialization, and it happens to end up looking like the second
version of the function declaraction, that's not obvious.

Quote:
Under the circumstances, that's probably not a helpful
addition to the language :-(

It's not an addition. It's not for nothing that we speak of
"type expressions" -- type declarations in C++ (and in C)
have an expression like syntax. And it's perfectly normal
that you can put any expression in parentheses without
modifying its meaning.

But the fix for this is to put the expression in parentheses.

No. The fix is to put more than the type expression in
parentheses. Since what is in parentheses must be either a type
expression (in a declarator) or an expression (in general), and
it doesn't have the correct syntax for the first, it must be the
second.

C++ declarations have a perfectly horrible syntax. In a certain
sense, I was being satirical with my "obviously", because there
is a very real sense that nothing is obvious in a C++
declaration. You have to analyse it carefully, even in the case
of relatively simple declarations. On the other hand, if you
understand the basics of how it works, for example, the
distinction between the declaration specifier and the
declarators, and how the type expressions in declarators work,
then the fact that the outer parentheses on a declarator doesn't
change anything is "obvious". Basically, it's obvious if you
are an expert, but you have to be more or less an expert to do
anything with declarations anyway.

Quote:
So clearly leaving out parentheses round an expression
modifies its meaning. And putting () round something can
change it from not-an-expression to an expression. That isn't
what you really expect parentheses to do.

Not really:-). The point is that parentheses can only enclose
expressions, so anything within parentheses must be an
expression. Even if it might be something else without the
parentheses.

Now to make it more fun: this only applies (obviously:-) to
parentheses used for grouping. When the parentheses are used
as a function call/function declaration operator, they don't
have this effect. Thus, in:
int f( A( b ) ) ;
the token sequence "A( b )" is enclosed in parentheses, but
these parentheses are a function declarator operator, so the
contents need not be an expression -- and in fact, the compiler
will interpret them as a declaration, rather than as an
expression. You need an extra pair of parentheses (which are
not operators) to force an expression.

Quote:
Note that the expression syntax needs the parentheses for
things like:
void f( int (*pf)() ) ;

Sure, but that is a function prototype, not a plain type (so
to speak).

Whatever. Try another example:
void f( int (*pa)[ 5 ] ) ;
The point is that the type expression in the declarator accepts
parentheses for grouping. Arbitrarily, in the same way normal
expressions accept the: "i = 5" and "(i = 5)" are both legal,
and mean the same thing (and if the expression isn't a full
expression, the parentheses may be necessary). And it would
require some sort of special rule to not allow them around the
full type expression.

Quote:
On the whole, I consider raw function prototypes as function
parameters as bad coding style.

I'm not sure what you mean here. In my first example, I
declared a parameter which was a pointer to a function; it's
something that I used relatively often in C. (In C++, it is
more usual to use a functional object.) In the second case, I
declared the parameter to be a pointer to an array of 5
elements. Again, it's not that usual, but it is legal.

Quote:
That is just about OK, but anything more complex than that
gets fairly rapidly unreadable (I've seen something with 2
function pointers, each with about 3 parameters, one of which
expected a function pointer passed to it).

C++ allows complex types. Sometimes, they're use is justified.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
ThosRTanner
Guest





PostPosted: Mon Aug 01, 2005 9:40 am    Post subject: Re: Reverse iterators Reply with quote


[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
ThosRTanner wrote:
[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Something is being done here that I dont understand. I
thought parameters had to have types, as in

const_reverse_iterator x(const_iterator idx);

So. That's pretty much the same thing as you had initially
written.

Only on the basis that you can do the replacement just below.

Or could I declare all functions in this way, for instance
replacing
int wibble(int a, float b)
with
int wibble(int(a), float(b))

Obviously.

If it was /that/ obvious, there wouldn't be a special name for
this problem!

It's obvious, given both versions, and asked the question, that
the second version is both legal, and equivalent to the first.
Yes, I got that far Sad


Quote:
If you're goal is to write a data declaration with
initialization, and it happens to end up looking like the second
version of the function declaraction, that's not obvious.

Under the circumstances, that's probably not a helpful
addition to the language :-(

It's not an addition. It's not for nothing that we speak of
"type expressions" -- type declarations in C++ (and in C)
have an expression like syntax. And it's perfectly normal
that you can put any expression in parentheses without
modifying its meaning.

But the fix for this is to put the expression in parentheses.

No. The fix is to put more than the type expression in
parentheses. Since what is in parentheses must be either a type
expression (in a declarator) or an expression (in general), and
it doesn't have the correct syntax for the first, it must be the
second.
Given that this whole problem even has its own name, I would question

the utility of being able to have int func(int(a)); as a declaration.
Are there any circumstances where you are allowed that and not allowed
int func(int a)? (OK, yes, I've just seen your int (*pa)[5]() thing
below).

Quote:
C++ declarations have a perfectly horrible syntax. In a certain
sense, I was being satirical with my "obviously", because there
is a very real sense that nothing is obvious in a C++
declaration. You have to analyse it carefully, even in the case
of relatively simple declarations. On the other hand, if you
understand the basics of how it works, for example, the
distinction between the declaration specifier and the
declarators, and how the type expressions in declarators work,
then the fact that the outer parentheses on a declarator doesn't
change anything is "obvious". Basically, it's obvious if you
are an expert, but you have to be more or less an expert to do
anything with declarations anyway.
Ah. Now I understand. The C++ syntax is designed so that only expert

C++ programmers can write and maintain C++ code ;-)

Quote:
So clearly leaving out parentheses round an expression
modifies its meaning. And putting () round something can
change it from not-an-expression to an expression. That isn't
what you really expect parentheses to do.

Not really:-). The point is that parentheses can only enclose
expressions, so anything within parentheses must be an
expression. Even if it might be something else without the
parentheses.

Now to make it more fun: this only applies (obviously:-) to
parentheses used for grouping. When the parentheses are used
as a function call/function declaration operator, they don't
have this effect. Thus, in:
int f( A( b ) ) ;
the token sequence "A( b )" is enclosed in parentheses, but
these parentheses are a function declarator operator, so the
contents need not be an expression -- and in fact, the compiler
will interpret them as a declaration, rather than as an
expression. You need an extra pair of parentheses (which are
not operators) to force an expression.

Note that the expression syntax needs the parentheses for
things like:
void f( int (*pf)() ) ;

Sure, but that is a function prototype, not a plain type (so
to speak).

Whatever. Try another example:
void f( int (*pa)[ 5 ] ) ;
Aaarrgh!


Quote:
The point is that the type expression in the declarator accepts
parentheses for grouping. Arbitrarily, in the same way normal
expressions accept the: "i = 5" and "(i = 5)" are both legal,
and mean the same thing (and if the expression isn't a full
expression, the parentheses may be necessary). And it would
require some sort of special rule to not allow them around the
full type expression.

On the whole, I consider raw function prototypes as function
parameters as bad coding style.

I'm not sure what you mean here. In my first example, I
declared a parameter which was a pointer to a function; it's
something that I used relatively often in C. (In C++, it is
more usual to use a functional object.) In the second case, I
declared the parameter to be a pointer to an array of 5
elements. Again, it's not that usual, but it is legal.
Yes, it's legal. No problem with that. But it isn't clear. Certainly

not as clear (IMO) as doing

typedef int somefunc_type(int (*a)[5]);

somefunc_type *pa;

This also helps slightly in that you can prototype your functions using
somefunc_type, which is a documentation aid, if nothing else.

Using typedefs to reduce parentheses can be rather helpful sometimes.

Quote:

That is just about OK, but anything more complex than that
gets fairly rapidly unreadable (I've seen something with 2
function pointers, each with about 3 parameters, one of which
expected a function pointer passed to it).

C++ allows complex types. Sometimes, they're use is justified.
Oh sure. But there are ways of making it easier to understand. And it

was a lot easier to understand once I had written typedefs for the
prototypes. It was much clearer it was a function that required 2
function pointers, not an entry in the obfuscated C competition.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Aug 02, 2005 10:39 am    Post subject: Re: Reverse iterators Reply with quote

ThosRTanner wrote:
Quote:
kanze (AT) gabi-soft (DOT) fr wrote:

[...]
Quote:
No. The fix is to put more than the type expression in
parentheses. Since what is in parentheses must be either a
type expression (in a declarator) or an expression (in
general), and it doesn't have the correct syntax for the
first, it must be the second.

Given that this whole problem even has its own name, I would
question the utility of being able to have int func(int(a));
as a declaration. Are there any circumstances where you are
allowed that and not allowed int func(int a)? (OK, yes, I've
just seen your int (*pa)[5]() thing below).

I think that there may even be a proposal before the committee
to special case the outer level parentheses, to forbid them in a
declaration. This makes a formal specification of the grammar
more than inelegant -- it's a pure hack. On the other hand, it
should be pretty easy to implement in the compiler, and would
probably solve the problem, from a pragmatic point of view.

The reason such a solution wasn't in C++ from the start is that
it is ugly and inelegant, and the no one really realized the
need for it.

Quote:
C++ declarations have a perfectly horrible syntax. In a
certain sense, I was being satirical with my "obviously",
because there is a very real sense that nothing is obvious
in a C++ declaration. You have to analyse it carefully,
even in the case of relatively simple declarations. On the
other hand, if you understand the basics of how it works,
for example, the distinction between the declaration
specifier and the declarators, and how the type expressions
in declarators work, then the fact that the outer
parentheses on a declarator doesn't change anything is
"obvious". Basically, it's obvious if you are an expert,
but you have to be more or less an expert to do anything
with declarations anyway.

Ah. Now I understand. The C++ syntax is designed so that only
expert C++ programmers can write and maintain C++ code Wink

Did you think that the C++ declaration syntax was "designed"? I
thought it just sort of came about, growing on the original C
syntax (which I think has been categorized as an experiment
which failed).

[...]
Quote:
I'm not sure what you mean here. In my first example, I
declared a parameter which was a pointer to a function; it's
something that I used relatively often in C. (In C++, it is
more usual to use a functional object.) In the second case,
I declared the parameter to be a pointer to an array of 5
elements. Again, it's not that usual, but it is legal.

Yes, it's legal. No problem with that. But it isn't
clear. Certainly not as clear (IMO) as doing

typedef int somefunc_type(int (*a)[5]);

somefunc_type *pa;

I used to think this, but now I'm not sure. The problem is that
using the data type is just as complicated, and typedef's don't
help there. Consider something like:

static C1* (C2::* const pf[])( int ) =
{
&C2::f1,
&C2::f2,
NULL
} ;

Using a typedef, you can definitly simplify the declaration:

typedef C1* (C2::*PMF)( int ) ;
static PMF const pf[] =
{ ... } ;

But you still have to understand the declaration in order to use
the variable:

C1* p = (c2Ptr->*pf[ i ])( j ) ;

There are two types of information hiding. One is good, when
the client not only doesn't see the information, but doesn't
need it in order to correctly use your code. The other is bad,
when the client code needs the information, but it isn't
immediately visible. The first declaration, without the
typedef, may not be particularly easy to read, but at least when
you see it, you know that the type is complicated, and that
expressions using it are likely to be complex as well. In the
second case -- it's just a plain, everyday table, what's so
complicated about that? My current feeling is that in the
second case, all you've done is lie to the reader.

Note that this is somewhat different from the case where you use
a typedef:

typedef std::map< std::string, std::vector< std::string > >
Map ;

The type Map is still used like a Map. You've not lied to the
user. At least, if the scope of the typedef is such that the
type of the map are more or less understandable.

And it is a lot different from cases where you do things like:
typedef int WidgetCount ;
Here, the typedef adds information, rather than hiding it.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
ThosRTanner
Guest





PostPosted: Tue Aug 02, 2005 2:34 pm    Post subject: Re: Reverse iterators Reply with quote


[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:
ThosRTanner wrote:
Ah. Now I understand. The C++ syntax is designed so that only
expert C++ programmers can write and maintain C++ code ;-)

Did you think that the C++ declaration syntax was "designed"? I
thought it just sort of came about, growing on the original C
syntax (which I think has been categorized as an experiment
which failed).

I was being optimistic!

Quote:
Yes, it's legal. No problem with that. But it isn't
clear. Certainly not as clear (IMO) as doing

typedef int somefunc_type(int (*a)[5]);

somefunc_type *pa;

I used to think this, but now I'm not sure. The problem is that
using the data type is just as complicated, and typedef's don't
help there. Consider something like:

static C1* (C2::* const pf[])( int ) =
{
&C2::f1,
&C2::f2,
NULL
} ;

Using a typedef, you can definitly simplify the declaration:

typedef C1* (C2::*PMF)( int ) ;
static PMF const pf[] =
{ ... } ;

The point of using the typedef is for where you require multiple
declarations, and you actually typedef the function prototype, not the
pointer. This makes code less error prone, and generally more
understandable. Especially when you have tables of pointers to
functions which take pointers to functions. Though I admit I haven't
tried that approach with pointers to member functions, and I'm not sure
how well it would work.

The point is not to simplify the table declaration but to get
consistency in the prototyping of the functions.

Quote:
But you still have to understand the declaration in order to use
the variable:

C1* p = (c2Ptr->*pf[ i ])( j ) ;
true. But that goes for all typedefs to a greater or lesser extent.

typedef int wibble;
wibble fred = 4.3;
is not a good idea.

Quote:
There are two types of information hiding. One is good, when
the client not only doesn't see the information, but doesn't
need it in order to correctly use your code. The other is bad,
when the client code needs the information, but it isn't
immediately visible. The first declaration, without the
typedef, may not be particularly easy to read, but at least when
you see it, you know that the type is complicated, and that
expressions using it are likely to be complex as well. In the
second case -- it's just a plain, everyday table, what's so
complicated about that? My current feeling is that in the
second case, all you've done is lie to the reader.
Um. It's not so much information handling, more of bundling identical

types together.

In the sense that the wibble function a takes a pointer to a
wibble_func function, then you can prototype all the functions you are
going to pass to wibble your wibble function with 'wibble_func
this_func, that_func, the_other_func;' and it makes it fairly clear to
the reader of the code that the wibble_func functions are going to be
used for a particular purpose. Though you still need to know what a
wibble_func actually is in order to write or call it.

Quote:
Note that this is somewhat different from the case where you use
a typedef:

typedef std::map< std::string, std::vector< std::string
Map ;

The type Map is still used like a Map. You've not lied to the
user. At least, if the scope of the typedef is such that the
type of the map are more or less understandable.
Yes, but unless all you are doing is passing it around, anyone who uses

Map still needs to know that it maps a string to a vector
Quote:
And it is a lot different from cases where you do things like:
typedef int WidgetCount ;
Here, the typedef adds information, rather than hiding it.

You still need to know a WidgetCount is an int though.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Wed Aug 03, 2005 1:38 pm    Post subject: Re: Reverse iterators Reply with quote

ThosRTanner wrote:
Quote:
kanze (AT) gabi-soft (DOT) fr wrote:
ThosRTanner wrote:

Ah. Now I understand. The C++ syntax is designed so that
only expert C++ programmers can write and maintain C++
code ;-)

Did you think that the C++ declaration syntax was
"designed"? I thought it just sort of came about, growing on
the original C syntax (which I think has been categorized as
an experiment which failed).

I was being optimistic!

In this case, I think it is called wishful thinking:-).

Quote:
Using a typedef, you can definitly simplify the declaration:

typedef C1* (C2::*PMF)( int ) ;
static PMF const pf[] =
{ ... } ;

The point of using the typedef is for where you require
multiple declarations, and you actually typedef the function
prototype, not the pointer. This makes code less error prone,
and generally more understandable. Especially when you have
tables of pointers to functions which take pointers to
functions. Though I admit I haven't tried that approach with
pointers to member functions, and I'm not sure how well it
would work.

The point is not to simplify the table declaration but to get
consistency in the prototyping of the functions.

Just for the record, I'm not that strongly against typedef's
here. I just wanted to point out that they aren't a panacea.
In one particular case where I had a table of pointers to member
functions:
-- version 1 used typedef,
-- version 2 used something like the above, for the reasons I
explained,
-- and in version 3, I replaced the pointer to member functions
with a pointer to a polymorphic functional object.
All things considered, I think that only the last version was
really readable. The real answer to complicated types isn't
typedef; the real answer is to replace them with a simpler type.

[...]

Quote:
And it is a lot different from cases where you do things like:
typedef int WidgetCount ;
Here, the typedef adds information, rather than hiding it.

You still need to know a WidgetCount is an int though.

No. That's actually the whole point here, that it isn't
necessarily an int. It is any type which conforms to a Count
requirements (and which has sufficient range).

For the rest, of course, you've made good points. The key to an
effective typedef is that the name exposes the important aspects
of its behavior. I can do many things with an int, but not all
of them would make sense if the int is maintaining a count of
widgets. So the name tells me something. And hides
implementation details which I presumably don't need to know;
the type can in theory change to long without any changes in my
code.

But the case is rarely black and white. And having a short,
succinct name which doesn't require declarations to span three
lines can be an asset in itself.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
richard@ex-parrot.com
Guest





PostPosted: Wed Aug 03, 2005 6:42 pm    Post subject: Re: Reverse iterators Reply with quote


[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote:
Quote:

I used to think this, but now I'm not sure. The problem is that
using the data type is just as complicated, and typedef's don't
help there. Consider something like:

static C1* (C2::* const pf[])( int ) =
{
&C2::f1,
&C2::f2,
NULL
} ;

I don't particularly object to declarations like this; nor for that
matter do I have problems with functions with function pointers as
parameters, e.g.

int atexit( void (*fn)() );

The one case that I do find simply obfuscates code to the point where
it is barely readable is when functions return function pointers, e.g.

void (*signal( int signum, void (*handler)(int) ))(int);

I recently came up with quite a nice way of increasing the readability
of this without introducing a typedef. (In this particular case, I
think the sighandler_t typedef does add to the readability of the
declaration; in other cases, however, I think it is simply hiding
information from the user.)

identity< void (*)(int) >::type
signal( int signum, void (*handler)(int) );

where identity is some identity metafunction such as the one in
boost::mpl. (I notice std::tr1 does not seem to have one. Although
it's trivial to roll your own, it's use is so prevelant in template
metaprogramming that it would surely be a suitable candidate for
inclusion.)

--
Richard Smith


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.