Strange constructor vs function declaration dichotomy.

21 views
Skip to first unread message

Ian Badcoe

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
Hi,
I don't think this is a FAQ:

If I have code as follows:

--- file.cpp ---

class Used {
float m_a;

public:
Used(float a) : m_a(a) {}
Used(Used &old) : m_a(old.m_a) {}
};

class User {
Used m_u1;
Used m_u2;

public:
User(Used u1, Used u2) : m_u1(u1), m_u2(u2) {}
};

int Function(User a);

int main() {
short x, y;

User a(Used(x), Used(y));

return Function(a);
}

--- end of file.cpp ---

then it fails to compile with an error (VC 5.0):

C:\Projects\temp\temp.cpp(24) : error C2664: 'Function' : cannot convert
parameter 1 from 'class User (class Used,class Used)' to 'class User'

and it isn't a compiler problem because gcc gives a very similar error.
Extensive trials and rearrangements pursuade me that the statement:

User a(Used(x), Used(y));

is being treated as a function declaration:

User a(Used x , Used y);

Any extra formatting (like changing the cast style) which makes it
unambiguously not a function declaration fixes the problem.

So, I think I've worked out what's going on but I'd welcome any
confirmation. In particular:

Is using constructors for unamed temporaries inside other constructors
commonly known to cause problems?

Is the syntax: int a(int(x), int(y)) (which does work) standard (is it
left
from pre-ansi or something)?

Can I do anything to make my original syntax work (like declaring the
classes/constructors differently) ?

Am I right about what's going wrong?

Thanks.

--
"I was quite frank with him that if he had a favor we could
do for him that would cost us something like $1M to do
that in return for switching browsers in the next few
months I would be open to doing that."

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Siemel Naran

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
On 21 Sep 1998 14:54:46 -0400, Ian Badcoe

>int Function(User a);
>
>int main() {
> short x, y;
>

> User a(Used(x), Used(y)); // LINE2
>
> return Function(a);
>}

Compiler thinks LINE2 is the definition of a function pointer.
The function pointer is called 'a'.
It takes two args, a Used and a Used, and returns a User.

The first variable's name is 'x'; the second is 'y'. These names are
just comments (function declarations never need to have names, but
naming is often a useful form of commenting).


If you could tell the compiler that 'x' is a constant, everything
would be solved. Eg,

User a(Used(1),Used(y)); // ok: creates object of type 'User'

In your case,
User a(Used((short)x),Used((short)y));

Another possibility is
User a=User(Used(x),Used(y));


Since the 1arg ctor for class Used is non-explicit, the solution is
actually even simpler:

User a(x,y); // best: short and sweet!
User a=User(x,y);

-----

>class Used {
> float m_a;
>
>public:
> Used(float a) : m_a(a) {}
> Used(Used &old) : m_a(old.m_a) {}
>};

Use const arg in copy ctor whenever possible -- which is most, if not
all, of the time.

Used(const Used &old) : m_a(old.m_a) {}

Actually, this particular class doesn't need a copy ctor. The
compiler generated one is fine.


> User(Used u1, Used u2) : m_u1(u1), m_u2(u2) {}

Also consider:

User(const Used& u1, const Used& u2) : m_u1(u1), m_u2(u2) {}


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

Alfred Kellner

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
Ian Badcoe <IanbXX.e...@gremlin.co.uk> wrote

> Hi,
> I don't think this is a FAQ:
>
[abbrev]
> class Used { ... };
> class User { ... };
> User a(Used(x), Used(y));
[...]

> Extensive trials and rearrangements pursuade me that the statement:
> User a(Used(x), Used(y));
> is being treated as a function declaration:
>
[...]

> Am I right about what's going wrong?
>
Yes.

<quote Draft>
8.2 Ambiguity resolution [dcl.ambig.res]
The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in 6.8 can also occur in the context
of a declaration. In that context, it surfaces as a choice between a
function declaration with a redundant set of parentheses around a
parameter name and an object declaration with a function-style
cast as the initializer.
Just as for statements, the resolution is to consider any construct
that
could possibly be a declaration a declaration. ...
....
S x(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
<quote>
So,
User a( (Used)x, (Used)y );
is considered as a object declaration.
--ALfred

Howard Gardner

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
I get the same baffling result from BCB 3. It does think
that User a is a function prototype.

Even more baffling: this verison of main works
dandy:

int main ( void )
{
float x = 0;
float y = 0;
User a ( x, y );
return Function( a );
}

If you leave the compiler to do the conversion
implicitly, it works. If you help it along by
specifying the conversion you want, it pukes.

Most confusing.

(BTW, just changing x and y to float doesn't
effect the error.)

--
mailto:hgar...@hgardner.com

Nikolai Pretzell

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to

>>>>>>>>>>>>>>>>>> Ursprüngliche Nachricht <<<<<<<<<<<<<<<<<<

Am 21.09.1998, 19:54:46, schrieb "Ian Badcoe"
<IanbXX.e...@gremlin.co.uk> zum Thema Strange constructor vs
function declaration dichotomy.:


> Hi,
> I don't think this is a FAQ:

> If I have code as follows:

> --- file.cpp ---


> int main() {
> short x, y;

> User a(Used(x), Used(y));

For reasons I do not understand, this line is seen as a function
pointer declaration. You can solve this by simply making clear, that
'Used' shell be a cast, by using the other way to express a cast:

User a( (Used)x, (Used)y);


Nikolai

Ian Badcoe

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
Thanks for the reply.

Siemel Naran wrote in message ...

>> User a(Used(x), Used(y)); // LINE2

>Compiler thinks LINE2 is the definition of a function pointer.
>The function pointer is called 'a'.
>It takes two args, a Used and a Used, and returns a User.

This is what I thought was happening (except it isn't a function pointer but
a declaration of a function itself) but it still seems odd. I never knew
that:

int F2(int(a), int(b)) {
...
}

was valid syntax for a function (although the compiler swallows it without
hesitation).


>In your case,
>User a(Used((short)x),Used((short)y));


This is something that I found worked.

>Another possibility is
>User a=User(Used(x),Used(y));


This also.

>Since the 1arg ctor for class Used is non-explicit, the solution is
>actually even simpler:


>User a(x,y); // best: short and sweet!
>User a=User(x,y);


This is true but in the real program they are explicit.

>Use const arg in copy ctor whenever possible -- which is most, if not
>all, of the time.


Certainly, these few lines were only typed out very fast as a minimal
illustration of the problem.

>Used(const Used &old) : m_a(old.m_a) {}


>Actually, this particular class doesn't need a copy ctor. The
>compiler generated one is fine.


True. However, can one trust the compiler generate copy ctor's to be
maximally efficient. In particular, many modern cpu's are happier to do a
copy with psuedo code like:

new.first = old.first;
new.second = old.second;
new.third = old.third;
new.fourth = old.fourth;

instead of a loop.

I also prefer, if copy construction is permitted, to have a function
explicitly present for it (so that I can put a break-point on it, for
example).

--
I've said it again and I'll say it before: time-travel is complicated!

Francis Glassborow

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
In article <slrn70d6oo....@fermi.ceg.uiuc.edu>, Siemel Naran
<sbn...@fermi.ceg.uiuc.edu> writes

>Another possibility is
>User a=User(Used(x),Used(y));
>
Which, unfortunately requires a public, non-explicit (I think) copy
ctor.


Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

hu...@anubisinc.com

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
In article <slrn70d6oo....@fermi.ceg.uiuc.edu>,

sbn...@KILL.uiuc.edu wrote:
> On 21 Sep 1998 14:54:46 -0400, Ian Badcoe
>
> >int Function(User a);
> >
> >int main() {
> > short x, y;
> >
> > User a(Used(x), Used(y)); // LINE2
> >
> > return Function(a);
> >}
>

Not exactly a function pointer but the declaration of a function.
Redundant ()
around dummy arguments are permitted so this is equivalent to
User a(User x, User y).

You could use User a((User(x), User(y))) or User a((User)x, (User)y)

Quote from Steve Clamage: 'If a statment *can be* interpreted as a simple
declaration, it *is* interpreted as a simple declaration. (For more details,
see the ARM.)'

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

Steve Clamage

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
In article 0...@nnrp1.news.uk.psi.net, "Ian Badcoe"
<IanbXX.e...@gremlin.co.uk> writes:

>class Used { ... };
>class User { ... };
>

> ...
> User a(Used(x), Used(y));

>Extensive trials and rearrangements pursuade me that the statement:
>
> User a(Used(x), Used(y));
>
>is being treated as a function declaration:
>

> User a(Used x , Used y);

Yes. The rule is that if a statement can possibly be a declaration,
it is a declaration. Redundent parens around the optional parameter name
in a function prototype are allowed, so the line in question declares
'a' to be a function returning type User, instead of creating an
object 'a' of type User.

Three ways to fix the problem:

1. Put parens around the type "Used" to create an old-style cast:


User a( (Used)x, (Used)y );

Redundent parens are not allowed around the parameter type, so
it can't be a function prototype.

2. Write a static_cast instead:
User a( static_cast<Used>(x), static_cast<Used>(y) );
Can't be a function prototype.

3. Make one or two explicit temps:
Used Ux(x);
Used Uy(y);
User a(Ux, Uy); // two temps for symmetry
Can't be a function prototype

It's a bit of ugliness in the language, and should be in a FAQ someplace.

---
Steve Clamage, stephen...@sun.com

Francis Glassborow

unread,
Sep 23, 1998, 3:00:00 AM9/23/98
to
In article <6u7v0d$c6g$1...@nnrp1.dejanews.com>, hu...@anubisinc.com writes

>You could use User a((User(x), User(y))) or User a((User)x, (User)y)

Carefull there is a really nasty Gotcha hanging around waiting to bite:

float x,y;

fn(x,y);
and
fn((x,y))
are different, one calls a function and passes it two arguments the
second passes a single argument (the value of the list (x,y))

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Siemel Naran

unread,
Sep 23, 1998, 3:00:00 AM9/23/98
to
On 22 Sep 1998 17:17:16 -0400, Ian Badcoe

>This is what I thought was happening (except it isn't a function pointer but
>a declaration of a function itself) but it still seems odd. I never knew
>that:
>
>int F2(int(a), int(b)) {
> ...
>}
>
>was valid syntax for a function (although the compiler swallows it without
>hesitation).

Parenthesis are necessary for const char * arguments with no names and
default values:

void print(const char *="Hello World"); // error: in place mult oper!
void print(const char (*)="Hello World"); // ok

>>Use const arg in copy ctor whenever possible -- which is most, if not
>>all, of the time.

>Certainly, these few lines were only typed out very fast as a minimal
>illustration of the problem.

OK, but next time be more careful.

>>Actually, this particular class doesn't need a copy ctor. The
>>compiler generated one is fine.

>True. However, can one trust the compiler generate copy ctor's to be
>maximally efficient. In particular, many modern cpu's are happier to do a
>copy with psuedo code like:

The optimizer's job is to find the fastest possible way to copy the data
elements. Maybe it will use a single memcpy. Since this sort of thing
is very common (copying elements from one POD-like struct to another),
I'm sure optimizers are advanced enough to do a good job.


--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

unread,
Sep 23, 1998, 3:00:00 AM9/23/98
to
Francis Glassborow <fran...@robinton.demon.co.uk> wrote:
> Siemel Naran <sbn...@fermi.ceg.uiuc.edu> writes
>>Another possibility is
>>User a=User(Used(x),Used(y));
>
>Which, unfortunately requires a public, non-explicit (I think) copy
>ctor.

The "explicit" keyword doesn't affect the copy constructor.
However, there might not be a public Used::Used(Used const&)
at all. This works:

User a(static_cast<Used>(x),Used(y));

--
Nathan Myers
n...@nospam.cantrip.org http://www.cantrip.org/

Paul Grealish

unread,
Sep 23, 1998, 3:00:00 AM9/23/98
to
Nathan Myers wrote:
>
> (snip)

> The "explicit" keyword doesn't affect the copy constructor.
> (snip)

It does under MSVC++5.0:

Foo foo1;
Foo foo2(foo1); // Legal
Foo foo3 = foo1; // Illegal if copy ctor is explicit

--
+---------------------------------+
| Paul Grealish |
| GEOPAK-TMS Limited |
| Cambridge, England |
| paul.g...@uk.geopak-tms.com |
+---------------------------------+

Andrei Alexandrescu

unread,
Sep 23, 1998, 3:00:00 AM9/23/98
to

Ian Badcoe wrote in message <36066...@nnrp1.news.uk.psi.net>...

>Hi,
> I don't think this is a FAQ:
>
>If I have code as follows:


Hi guys,

Very interesting thread.
I have two questions related to this ambiguity. I recall vaguely that Bjarne
advises one to mitigate this ambiguity by using the almost forgot auto
keyword:

User a(Used(x), Used(y)); // declares function a
auto User a(Used(x), Used(y)); // defines auto variable b, as intended

Is this correct? VC5 still considers you want to declare a funstion and
issues an error.
And by the way, is the auto keyword deprecated by the current standard?
Thanks.

Andrei

jka...@otelo.ibmmail.com

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
In article <6u7v0d$c6g$1...@nnrp1.dejanews.com>,

hu...@anubisinc.com wrote:
> In article <slrn70d6oo....@fermi.ceg.uiuc.edu>,
> sbn...@KILL.uiuc.edu wrote:
> > On 21 Sep 1998 14:54:46 -0400, Ian Badcoe
> >
> > >int Function(User a);
> > >
> > >int main() {
> > > short x, y;
> > >
> > > User a(Used(x), Used(y)); // LINE2
> > >
> > > return Function(a);
> > >}
> >
>
> Not exactly a function pointer but the declaration of a function.
> Redundant ()
> around dummy arguments are permitted so this is equivalent to
> User a(User x, User y).
>
> You could use User a((User(x), User(y))) or User a((User)x, (User)y)

You can't use the first, at least not with the same semantics. The first
constructs a with a single argument, not two. The comma in this statement
is a comma operator, and not a separator.

--
James Kanze +33 (0)1 39 23 84 71 mailto: ka...@gabi-soft.fr
+49 (0)69 66 45 33 10 mailto: jka...@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orientée objet --
-- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

jka...@otelo.ibmmail.com

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
In article <slrn70d6oo....@fermi.ceg.uiuc.edu>,
sbn...@KILL.uiuc.edu wrote:
> On 21 Sep 1998 14:54:46 -0400, Ian Badcoe
>
> >int Function(User a);
> >
> >int main() {
> > short x, y;
> >
> > User a(Used(x), Used(y)); // LINE2
> >
> > return Function(a);
> >}
>
> Compiler thinks LINE2 is the definition of a function pointer.

LINE2 is the definition of an external function. This is not what the
compiler thinks; it is what the standard says.

> The function pointer is called 'a'.

It's an external function, not a pointer. (Not that the difference is
going to help you.)

> It takes two args, a Used and a Used, and returns a User.
>

> The first variable's name is 'x'; the second is 'y'. These names are
> just comments (function declarations never need to have names, but
> naming is often a useful form of commenting).
>
> If you could tell the compiler that 'x' is a constant, everything
> would be solved. Eg,
>
> User a(Used(1),Used(y)); // ok: creates object of type 'User'

There's also the classical solution from Fortran:

User a( Used( x + 0 ) , Used( y ) ) ;

Your suggestion only works if my argument is a constant, and mine only
works if the argument supports arithmetic. A more general solution
is to use a different form of cast, either:

User a( (Used)( x ) , (Used)( y ) ) ;

or:

User a( static_cast< Used >( x ) , static_cast< Used >( y ) ) ;

> In your case,
> User a(Used((short)x),Used((short)y));

Basically the same as the Fortran solution: make the argument an rvalue.

> Another possibility is
> User a=User(Used(x),Used(y));

Fails if User doesn't support copy (a frequent case).

> Since the 1arg ctor for class Used is non-explicit, the solution is
> actually even simpler:
>
> User a(x,y); // best: short and sweet!
> User a=User(x,y);

Question of style: I tend to eschew implicit conversions, except in the
case of "hidden" classes (Proxies).

Francis Glassborow

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
In article <3608D8...@uk.geopak-tms.com>, Paul Grealish
<paul.g...@uk.geopak-tms.com> writes

>Nathan Myers wrote:
>>
>> (snip)
>> The "explicit" keyword doesn't affect the copy constructor.
>> (snip)
>
>It does under MSVC++5.0:
>
> Foo foo1;
> Foo foo2(foo1); // Legal
> Foo foo3 = foo1; // Illegal if copy ctor is explicit

Nathan will correct me if I am wrong, but I always understood that this
behaviour (of VC++ 5) is correct.

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alexandre Oliva

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
Andrei Alexandrescu <alexan...@micromodeling.com> writes:

> I have two questions related to this ambiguity. I recall vaguely
> that Bjarne advises one to mitigate this ambiguity by using the
> almost forgot auto keyword:

> User a(Used(x), Used(y)); // declares function a
> auto User a(Used(x), Used(y)); // defines auto variable b, as intended

It doesn't solve the problem, as some member of the standard committee
(was that you, Steve?) has explained to me that the decision on
whether a declaration is a function declaration or an object
definition must be purely syntactic. Syntactically, `auto' can be
part of any declaration, but, semantically, it is not valid in
function declarations. So, the second example must be parsed as an
invalid function declaration, not as an object declaration.

Note, however, that the `auto' keyword can be used to disambiguate a
declaration from an expression statement. But then, this doesn't gain
much, because such ambiguous declaration-statements must be parsed as
declarations even if `auto' is not specified.

> And by the way, is the auto keyword deprecated by the current standard?

Nope

--
Alexandre Oliva
mailto:ol...@dcc.unicamp.br mailto:aol...@acm.org
http://www.dcc.unicamp.br/~oliva
Universidade Estadual de Campinas, SP, Brasil

Ian Badcoe

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
Amongst many other kind people, jka...@otelo.ibmmail.com wrote in message
<6ubfpq$p1$1...@nnrp1.dejanews.com>...

---

>Question of style: I tend to eschew implicit conversions, except in the
>case of "hidden" classes (Proxies).


Us also.

---

I'm just posting to thank everybody for these useful explanations.

Basically to summarize:

If ever there is doubt, treat a statement as a declaration rather
and an definition:

User a(Used (x), Used(y)); // function declaration
User a((Used)x, (Used)y); // object definition

So it is a function declaration vs object definition; does anyone know any
other circumstances with the same problem?

--
I've said it again and I'll say it before: time-travel is complicated!

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Siemel Naran

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
On 24 Sep 1998 00:57:26 -0400, jka...@otelo.ibmmail.com
>In article <slrn70d6oo....@fermi.ceg.uiuc.edu>,

>> Compiler thinks LINE2 is the definition of a function pointer.
>
>LINE2 is the definition of an external function. This is not what the
>compiler thinks; it is what the standard says.

The compiler thinks this because the standard says so!


>> The function pointer is called 'a'.

>It's an external function, not a pointer. (Not that the difference is
>going to help you.)

I suppose it could help in some cases. You can make an array of function
pointers, but not an array of functions (which implies that you can take
the sizeof of a func ptr but not a func).

Anyway, the use of func declarations inside func bodies had me stumped
for a while. But I think the reason is to hide overloaded funcs that
would otherwise be preferred because they make a more direct match.
For example,


#include <iostream>

void f(int i) { std::cout << "int=" << i << '\n'; }
void f(short s) { std::cout << "short=" << s << '\n';}

int main()
{
f(1); // calls f(int)
void f(short);
f(1); // fooled you!
}

>Question of style: I tend to eschew implicit conversions, except in the
>case of "hidden" classes (Proxies).

Right. Most single arg ctors are explicit anyway.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Vaclav Barta

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
Siemel Naran wrote:
> Parenthesis are necessary for const char * arguments with no names and
> default values:
>
> void print(const char *="Hello World"); // error: in place mult oper!
> void print(const char (*)="Hello World"); // ok
void print(const char * = "Hello World");
is an alternative (which I would prefer - and naming the
argument would be the best way...).

Bye
Vasek
--
I have a search engine, too!
http://www.locus.cz/locus/

Siemel Naran

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
On 24 Sep 1998 16:08:38 -0400, Alexandre Oliva <ol...@dcc.unicamp.br> wrote:
>Andrei Alexandrescu <alexan...@micromodeling.com> writes:

>> And by the way, is the auto keyword deprecated by the current standard?

>Nope

So give an example of what "auto" is good for.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

David Abrahams

unread,
Sep 24, 1998, 3:00:00 AM9/24/98
to
On 24 Sep 1998 16:52:49 -0400, "Ian Badcoe"
<IanbXX.e...@gremlin.co.uk> wrote, in an article on
disambiguating function declarations and object definitions:

>I'm just posting to thank everybody for these useful explanations.
>
>Basically to summarize:
>
> If ever there is doubt, treat a statement as a declaration rather
>and an definition:

I'd like to take this opportunity to encourage implementors to provide
a warning which is triggered if anyone ever declares a function within
a function body. Although legal, it is rarely useful, and usually a
sign of poor code.

Unless there is a case where it is indispensable, I would even urge
that this use be deprecated!

Also let me point out: this is another excellent reason to step
through each line of code you write in a debugger. I've seen grizzled
C++ veterans make this mistake; it can trip you up, too!

-Dave

David Kastrup

unread,
Sep 25, 1998, 3:00:00 AM9/25/98
to
sbn...@localhost.localdomain (Siemel Naran) writes:

> On 24 Sep 1998 00:57:26 -0400, jka...@otelo.ibmmail.com
> >In article <slrn70d6oo....@fermi.ceg.uiuc.edu>,
>
> >> Compiler thinks LINE2 is the definition of a function pointer.
> >
> >LINE2 is the definition of an external function. This is not what the
> >compiler thinks; it is what the standard says.
>
> The compiler thinks this because the standard says so!

Of course the compiler does not think. This is the reason he gets it
right most of the time (compiler writers need to get it only right
once and have tests for that, and the compiler will take it from
there without thinking).

In contrast to humans that think, and therefore get it wrong quite
often. I really don't like the mass of ambiguities concerning casts,
declarations and function calls C++ provides. Makes it too likely to
think the wrong things.

--
David Kastrup Phone: +49-234-700-5570
Email: d...@neuroinformatik.ruhr-uni-bochum.de Fax: +49-234-709-4209
Institut für Neuroinformatik, Universitätsstr. 150, 44780 Bochum, Germany

Alexandre Oliva

unread,
Sep 25, 1998, 3:00:00 AM9/25/98
to
Siemel Naran <sbn...@fermi.ceg.uiuc.edu> writes:

> On 24 Sep 1998 16:08:38 -0400, Alexandre Oliva <ol...@dcc.unicamp.br> wrote:
>> Andrei Alexandrescu <alexan...@micromodeling.com> writes:

>>> And by the way, is the auto keyword deprecated by the current standard?

>> Nope

> So give an example of what "auto" is good for.

I don't think it is useful. I just said it was not deprecated in the
Standard. :-)

--
Alexandre Oliva
mailto:ol...@dcc.unicamp.br mailto:aol...@acm.org
http://www.dcc.unicamp.br/~oliva
Universidade Estadual de Campinas, SP, Brasil

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Nathan Myers

unread,
Sep 25, 1998, 3:00:00 AM9/25/98
to
Siemel Naran<sbn...@KILL.uiuc.edu> wrote:
> ... the use of func declarations inside func bodies had me stumped

>for a while. But I think the reason is to hide overloaded funcs that
>would otherwise be preferred because they make a more direct match.
>For example,
>
>void f(int i);
>void f(short s);

>
>int main()
>{
> f(1); // calls f(int)
> void f(short);
> f(1); // fooled you!
>}

Interestingly, Koenig lookup can defeat this intention:

struct A {};
struct B : A {};
void f(A*);
void f(B*);
int g(B* p)
{
void f(A*); // try to hide f(B*)
f(p); // still finds f(B*)!
}

Here's another interesting case:

struct A {};
struct B {};
void f(A*);
void f(B*);
struct C : A, B {};
int g(C* p)
{
void f(A*); // try to hide f(B*)
f(p); // still ambiguous!
}

I believe it was Josee Lajoie (co-author of C++ Primer) who first
posted similar observations.

Francis Glassborow

unread,
Sep 26, 1998, 3:00:00 AM9/26/98
to
In article <orvhmbj...@araguaia.dcc.unicamp.br>, Alexandre Oliva
<ol...@dcc.unicamp.br> writes

>I don't think it is useful. I just said it was not deprecated in the
>Standard. :-)

It is a standing riposte in the C standards committees that you can have
nay new keyword you like as long as it is spelt a,u,t,o. BTW 'register'
is very close to being as useless (no it does not ask the compiler to
place the variable in a register - it actually advises that you want the
variable in fast access storage. Unfortunately most compilers can do
better by ignoring it in all cases but that where it is not allowed:)

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Sep 26, 1998, 3:00:00 AM9/26/98
to
In article <6ugto8$3ar$1...@shell7.ba.best.com>, Nathan Myers
<n...@nospam.cantrip.org> writes

>Interestingly, Koenig lookup can defeat this intention:

Yes Koenig lookup provides quite a few surprises for programmers who are
thinking in traditional idioms. It is one of those concepts that we are
all going to have to move closer to intuitive.

Siemel Naran

unread,
Sep 27, 1998, 3:00:00 AM9/27/98
to
On 26 Sep 1998 15:23:49 -0400, Francis Glassborow

>Yes Koenig lookup provides quite a few surprises for programmers who are
>thinking in traditional idioms. It is one of those concepts that we are
>all going to have to move closer to intuitive.

OK, but I think it is the concept of function hiding that is the more
non-intuitive. Koenig lookup seems to prevent function hiding, so it
is more intuitive. Anyway, all this is new to me, so let's see if I
got it straight.

---

>From [basic.koenig.lookup]

For a function call f(T):

T associated classes associated namespaces
------------------------------------------------------------------
fundamental type empty empty
user class T and its base classes their namespaces
function-pointer classes of arg+return their namespaces
member-pointer classes of arg+return+X their namespaces


-----

#include <iostream>

struct Base { };
struct Derived : public Base { };

void f(int ) { std::cout << "int\n" ; }
void f(short) { std::cout << "short\n"; }

void g(const Base &) { std::cout << "const Base&\n" ; }
void g(const Derived&) { std::cout << "const Derived&\n"; }

int main()
{
f(1); // calls f(int)

void f(short); // LINE2
f(1); // calls f(short)

g(Derived()); // calls f(const Derived&)
void g(const Base&); // LINE5
g(Derived()); // calls f(const Derived&)
}

/*

In f(1) on LINE3, T is int.
The associated classes are none
The associated namespaces are none
So we pick the first f(...) func we find, namely f(short) on LINE2

In g(Derived()), T is Derived.
The associated classes are ::Derived and ::Base
The associated namespaces are ::
We search the associated namespaces for viable f(...) funcs
This gives f(const Base&) and f(const Derived&)
f(const Derived&) is better as it is a more direct match
Since we've found something, we may ignore LINE5

*/

-----

namespace myspace
{
struct Base { };
struct Derived : public Base { };
}

void g(const myspace::Base &) { std::cout << "const Base&\n" ; }
void g(const myspace::Derived&) { std::cout << "const Derived&\n"; }

int main()
{
g(myspace::Derived()); // calls f(const Derived&)
void g(const myspace::Base&); // LINE2
g(myspace::Derived()); // calls f(const Base&)
}

On LINE3, in g(T), T is myspace::Derived.
The associated classes are ::myspace::Derived and ::myspace::Base
The associated namespaces are ::myspace
::myspace doesn't have any f(...) funcs
So we do the normal lookup
The first relevant func is the one defined on LINE2

---

In view of this, what are the dangers of "using namespace something".

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Kirk Swenson

unread,
Oct 1, 1998, 3:00:00 AM10/1/98
to
In article <360abf03....@news.motu.com>, abra...@spam.motu.com wrote:
>I'd like to take this opportunity to encourage implementors to provide
>a warning which is triggered if anyone ever declares a function within
>a function body. Although legal, it is rarely useful, and usually a
>sign of poor code.

There may be people out there for whom such a broad warning would be
inconvenient. The goal should be to generate the warning when there is a
reasonable possibility of ambiguity, i.e. when the compiler may not be
interpreting the code the way the programmer intended, rather than as an
enforcement of programming style. Warning about function declarations
within a function body that return a user-defined type would catch all of
the instances in which I've been bitten by this problem. There may be
better heuristics for when to generate the warning, but this is a simple
one that would have saved me a bit of time over the years.
--
Kirk Swenson
Senior Software Engineer
Key Curriculum Press
kswe...@keypress.com

Reply all
Reply to author
Forward
0 new messages