Q:function call.

84 views
Skip to first unread message

RICO

unread,
Nov 4, 2001, 8:57:04 PM11/4/01
to
Hi, everyone:
I am doubted by the code snippe:

struct T_
{
T_(const T& t) { }
};

struct D_ : T_
{
D_() {}
D_(const D& d)
{
T_::T_(d); // 1
this->T_::T_(d); // 2
Base::operator=(d); // 3
}
};

My question is what is the different between 1 and 2? I understand that
the expression of 1 equal call of *T_(d)*, but the second expression give me
more doubts, why I can call ctor directly but it is don't create new object?
Another one is the expression 3 can get correct result, but I don't call it
from pointer of *this*. Can I find some corresponding content in standard of
c++?

Thanks for any reply.

-Rico, bye.

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

Francis Glassborow

unread,
Nov 5, 2001, 9:54:32 AM11/5/01
to
In article <9s4r0l$ht4$1...@mail.cn99.com>, RICO <y_...@btamail.net.cn>
writes

>Hi, everyone:
> I am doubted by the code snippe:
>
> struct T_
> {
> T_(const T& t) { }
> };
>
> struct D_ : T_
> {
> D_() {}
> D_(const D& d)

OK, so you are declaring and defining the copy ctor. At this stage you
have a new D object that has been default initialised (i.e. it calls the
default ctor of T_. Please note that carefully). It would have been more
normal to have used a ctor init list to take control of the
initialisation process -- to see what is happening try defining a
default ctor for T_ and then instrument -- print a message from the body
-- the two T_ ctors.

> {
> T_::T_(d); // 1
creates and immediately destroys a T object that is a copy of the T_
part of D_ (try defining and instrumenting a dtor for T_)


> this->T_::T_(d); // 2

should do the same as 1.

> Base::operator=(d); // 3

should give an error message unless you have Base defined somewhere with
an assignment that can take a T_. However I think you meant
T_::operator= in which case it copies, by assignment, the T_ part of d
to the T_ part of the object that has been created by the call of the
copy ctor for D_

> }
> };
>
> My question is what is the different between 1 and 2?

None, but I think you have a misconception as to what either does.

> I understand that
>the expression of 1 equal call of *T_(d)*, but the second expression give me
>more doubts, why I can call ctor directly but it is don't create new object?

It does, what makes you think it does not?

>Another one is the expression 3 can get correct result, but I don't call it
>from pointer of *this*. Can I find some corresponding content in standard of
>c++?

It is all part of the fundamentals of the language, and so the rules are
rather distributed across the Standard, which is not intended to be a
tutorial.

Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

James Kanze

unread,
Nov 5, 2001, 12:21:57 PM11/5/01
to
"RICO" <y_...@btamail.net.cn> wrote in message
news:<9s4r0l$ht4$1...@mail.cn99.com>...

> I am doubted by the code snippe:

As you should be.

> struct T_
> {
> T_(const T& t) { }
> };

> struct D_ : T_
> {
> D_() {}
> D_(const D& d)
> {
> T_::T_(d); // 1

This constructs a temporary T_, initializing it with the T_ part of
the parameter. It then immediately destructs the temporary, without
doing anything with it.

> this->T_::T_(d); // 2

IMHO, this shouldn't compile. A constructor is NOT a member function,
at least not in the normal sense, and so is not an acceptable argument
on the right side of an ->.

> Base::operator=(d); // 3

Supposing that there is a typedef _T Base somewhere, there is no real
problem with this one, although it seems a little surprising in this
context. This basically assigns the _T from the _T part of the
argument.

> }
> };

> My question is what is the different between 1 and 2?

1 is legal, but doesn't do anything useful, 2 is illegal.

> I understand that the expression of 1 equal call of *T_(d)*, but the
> second expression give me more doubts, why I can call ctor directly
> but it is don't create new object?

You can't.

> Another one is the expression 3 can get correct result, but I don't
> call it from pointer of *this*.

Yes you do. The function is first looked up as if it were a member
function, using an implicit this->; global functions are only
considered if this lookup fails.

> Can I find some corresponding content in standard of c++?

Of course:
1. 5.2.3 Explicit type conversion (functional notation)
2. 5.2.5 Class member access and 3.4.5 Class member access (for the
name lookup rules).
3. 5.2.2 Function call and 3.4.3 Qualified name lookup

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

Carl Daniel

unread,
Nov 5, 2001, 4:48:58 PM11/5/01
to

"RICO" <y_...@btamail.net.cn> wrote in message
news:9s4r0l$ht4$1...@mail.cn99.com...
> Hi, everyone:
> I am doubted by the code snippe:
>
> struct T_
> {
> T_(const T& t) { }
> };
>
> struct D_ : T_
> {
> D_() {}
> D_(const D& d)
> {
> T_::T_(d); // 1
> this->T_::T_(d); // 2
> Base::operator=(d); // 3
> }
> };
>
> My question is what is the different between 1 and 2? I understand
that
> the expression of 1 equal call of *T_(d)*, but the second expression give
me
> more doubts, why I can call ctor directly but it is don't create new
object?
> Another one is the expression 3 can get correct result, but I don't call
it
> from pointer of *this*. Can I find some corresponding content in standard
of
> c++?
>

After adding a default constructor for T_, and fixing various typos, Comeau
C++ has the following to say:
"29989.c", line 12: error: a constructor or destructor may not have its
address taken
T_::T_(d); // 1
^

"29989.c", line 13: error: a constructor or destructor may not have its
address taken


this->T_::T_(d); // 2

^

I believe Comeau is correct about two things:
1. Since you supplied a constructor, you must supply a default constructor -
the compiler-generated default constructor is suppressed if any user defined
constructor(s) are present - 12.1 (5).

2. The calls at //1 and //2 are both illegal - calling a constructor
explicitly is not allowed - 12.1 (2) "because constructors don't have names
they are never found during name lookup".

I'm guessing that you're using some version of MSVC, which I know allows
calling constructors directly. IIRC, //1 will create and immediately
destroy a temporary, while //2 will call the T_::T_ constructor on *this.
MSVC allows this syntax to have the function normally provided by "placement
new".

-cd

Carl Daniel

unread,
Nov 5, 2001, 6:41:02 PM11/5/01
to

"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.01110...@posting.google.com...

> "RICO" <y_...@btamail.net.cn> wrote in message
> news:<9s4r0l$ht4$1...@mail.cn99.com>...
>
> > I am doubted by the code snippe:
>
> As you should be.
>
> > struct T_
> > {
> > T_(const T& t) { }
> > };
>
> > struct D_ : T_
> > {
> > D_() {}
> > D_(const D& d)
> > {
> > T_::T_(d); // 1
>
> This constructs a temporary T_, initializing it with the T_ part of
> the parameter. It then immediately destructs the temporary, without
> doing anything with it.
>

Doesn't 12.1 (2) make this illegal?

> > this->T_::T_(d); // 2
>

And this as well?

-cd

Carl Daniel

unread,
Nov 5, 2001, 10:10:30 PM11/5/01
to

"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:ElnE1KA$fm57...@ntlworld.com...

> In article <9s4r0l$ht4$1...@mail.cn99.com>, RICO <y_...@btamail.net.cn>
> writes
> >Hi, everyone:
> > I am doubted by the code snippe:
> >
> > struct T_
> > {
> > T_(const T& t) { }
> > };
> >
> > struct D_ : T_
> > {
> > D_() {}
> > D_(const D& d)
>
[snip]

>
> > {
> > T_::T_(d); // 1
> creates and immediately destroys a T object that is a copy of the T_
> part of D_ (try defining and instrumenting a dtor for T_)

I believe 12.1 (2) makes this line illegal.

> > this->T_::T_(d); // 2

And this one as well.

[snip]

> >
> > My question is what is the different between 1 and 2?
>
> None, but I think you have a misconception as to what either does.
>
> > I understand that
> >the expression of 1 equal call of *T_(d)*, but the second expression give
me
> >more doubts, why I can call ctor directly but it is don't create new
object?
>
> It does, what makes you think it does not?

I belive MSVC allow this type of call, and it (re)runs the constructor on
the indicated object - the effect of placement new, but with a non-standard
syntax. IIRC, the MFC "collection classes" use this technique to
default-construct members when the container grows.

-cd

Francis Glassborow

unread,
Nov 6, 2001, 10:36:24 AM11/6/01
to
In article <x7EF7.19282$yl3.351...@newssvr21.news.prodigy.com>, Carl
Daniel <cpda...@pacbell.net> writes

>> > {
>> > T_::T_(d); // 1
>> creates and immediately destroys a T object that is a copy of the T_
>> part of D_ (try defining and instrumenting a dtor for T_)
>
>I believe 12.1 (2) makes this line illegal.
>
>> > this->T_::T_(d); // 2
>
>And this one as well.

I am not sure that looks like an explicit type conversion to me.
int i = 3;
(long)i;
is well formed isn't it? Even though it actually has no effect. So
isn't:

long(i);

also valid?

then what about:

int(i);

??

And the subclause and paragraph you reference identifies conversion via
functional notation as an exception.

I was actually thinking of the case where it is providing a temporary in
a function call where the first form is valid, and I sort of suspect
that the second one is as well.


Francis Glassborow
I offer my sympathy and prayers to all those who are suffering
as a result of the events of September 11 2001.

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

Sebastian Kapfer

unread,
Nov 6, 2001, 12:06:39 PM11/6/01
to
In article <9s4r0l$ht4$1...@mail.cn99.com>, RICO writes...

| Hi, everyone:
| I am doubted by the code snippe:
|
| struct T_
| {
| T_(const T& t) { }
| };
|
| struct D_ : T_
| {
| D_() {}
| D_(const D& d)
| {
| T_::T_(d); // 1
| this->T_::T_(d); // 2
| Base::operator=(d); // 3
| }
| };
|
| My question is what is the different between 1 and 2?

Both are illegal in C++.

| I understand that
| the expression of 1 equal call of *T_(d)*, but the second expression give me
| more doubts, why I can call ctor directly but it is don't create new object?

You can't call constructors using that syntax. I know of a certain
compiler that accepts such code, but it is wrong.

new( static_cast<T_ *>(this) ) T_(d);

would invoke the constructor for *this, but imagine what happens then:

D_(const D_ &d)
// default constructing the T_ part of *this
{
// another call of the constructor, constructing into
// an already existing object -> BAD
new( static_cast<T_ *>(this) ) T_(d);
}

The correct syntax is:

D_(const D_ &d) : T_(d)
{
}

| Another one is the expression 3 can get correct result, but I don't call it
| from pointer of *this*. Can I find some corresponding content in standard of
| c++?

D_(const D_ &d)
{
T_::operator=(d);
}

I don't have a quote from the standard for you, but this works, if you
mean T_ where you write Base :) It might be less efficient than a call
to the copy constructor though. Because the T_ part is default-
constructed first, and then reassigned. It depends on your class if that
makes a difference.

sk

Carl Daniel

unread,
Nov 6, 2001, 12:26:33 PM11/6/01
to

"Francis Glassborow" <francis.g...@ntlworld.com> wrote in message
news:e$HizGB$W857...@ntlworld.com...

> In article <x7EF7.19282$yl3.351...@newssvr21.news.prodigy.com>, Carl
> Daniel <cpda...@pacbell.net> writes
> >> > {
> >> > T_::T_(d); // 1
> >> creates and immediately destroys a T object that is a copy of the T_
> >> part of D_ (try defining and instrumenting a dtor for T_)
> >
> >I believe 12.1 (2) makes this line illegal.
> >
> >> > this->T_::T_(d); // 2
> >
> >And this one as well.
>

[snip]

> And the subclause and paragraph you reference identifies conversion via
> functional notation as an exception.

12.1 (2) "...Because constructors do not have names, they are never found
during name lookup."

I read that to say that while T_(d) should behave as you suggest (due to the
exception), that T_::T_(d) is ill-formed, since T_ cannot be found as a name
within class T_.

Comeau rejects both of these, but with an odd "error: a constructor or
destructor may not have its address taken" message, which appears to derive
from 12.1 (12).

The second one must also be invalid according to the same reasoning.

That's how I read it anyway :)

-cd

James Kanze

unread,
Nov 6, 2001, 1:37:01 PM11/6/01
to
"Carl Daniel" <cpda...@pacbell.net> wrote in message
news:<FHzF7.19211$wq7.347...@newssvr21.news.prodigy.com>...

> "RICO" <y_...@btamail.net.cn> wrote in message
> news:9s4r0l$ht4$1...@mail.cn99.com...

> > I am doubted by the code snippe:

> > struct T_
> > {
> > T_(const T& t) { }
> > };

> > struct D_ : T_
> > {
> > D_() {}
> > D_(const D& d)
> > {
> > T_::T_(d); // 1
> > this->T_::T_(d); // 2
> > Base::operator=(d); // 3
> > }
> > };

> > My question is what is the different between 1 and 2? I
> > understand that the expression of 1 equal call of *T_(d)*, but the
> > second expression give me more doubts, why I can call ctor
> > directly but it is don't create new object? Another one is the
> > expression 3 can get correct result, but I don't call it from
> > pointer of *this*. Can I find some corresponding content in
> > standard of c++?

> After adding a default constructor for T_, and fixing various typos,
> Comeau C++ has the following to say:
> "29989.c", line 12: error: a constructor or destructor may not have its
> address taken
> T_::T_(d); // 1
> ^

Strange. I would call this an error in the compiler. A constructor
obviously cannot have it's address taken, of course. In fact, a
constructor cannot even be named, so I don't quite know what kind of
syntax you would need to take its address.

In this case, the first T_, of course, designates the class T_, and
specifies the scope for the name lookup which follows. And because of
9/2, the scoped lookup finds the name of the class. In a declaration,
of course, naming the class within the scope of the class has a
special signification, and results in declaring a constructor. But
here, we are not in a declaration (or are we, see below); in an
expression, the name lookup finds the class name, which means that we
have a function style cast.

The reason I'm not sure is that a statement of the form:

T_::T_ d ;

sure looks a lot like a declaration, and adding parentheses around the
d doesn't change anything. It's not a legal declaration, because it
results in declaring d twice. But according to 6.8/1, "An
expression-statement with a function-style explicit type conversion
[what we have here] as its leftmost subexpression can be
indistinguishable from a declaration where the first declarator starts
with a (. In those cases the statement is a declaration."

So you (and Comeau) are right that the statement is illegal, but it is
illegal because it is an attempt to define a variable d, and not for
any reason involving the constructor.

> "29989.c", line 13: error: a constructor or destructor may not have its
> address taken
> this->T_::T_(d); // 2
> ^

> I believe Comeau is correct about two things:

> 1. Since you supplied a constructor, you must supply a default
> constructor - the compiler-generated default constructor is
> suppressed if any user defined constructor(s) are present - 12.1
> (5).

> 2. The calls at //1 and //2 are both illegal - calling a constructor
> explicitly is not allowed - 12.1 (2) "because constructors don't
> have names they are never found during name lookup".

Calling the constructor isn't illegal. There just isn't any possible
syntax that would do it, since the constructor can't be named. Case 1
is illegal because the expression is ambiguous, and so is taken as a
declaration, which results in a duplicate declaration. Otherwise,
name injection results in it being a legal function style type
conversion. Case 2 is illegal simply because there is no syntax in
the language that allows -> to be followed by a type name (which is
what T_::T_ is).

From the error messages, it would look like Comeau is getting the name
injection wrong. Which surprises me a little, because if memory
serves me correctly, it was EDG who developed the idea of name
injection.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

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

Ron Natalie

unread,
Nov 6, 2001, 5:19:46 PM11/6/01
to

>
> Strange. I would call this an error in the compiler. A constructor
> obviously cannot have it's address taken, of course. In fact, a
> constructor cannot even be named, so I don't quite know what kind of
> syntax you would need to take its address.

Your construct is illegal. The compiler is trying to make a guess
as to what it is you are trying to do. Technically, all the compiler
is required to generate is a "diagnostic" the contents of which are
not specified by the standard.

>
> In this case, the first T_, of course, designates the class T_, and
> specifies the scope for the name lookup which follows. And because of
> 9/2, the scoped lookup finds the name of the class. In a declaration,
> of course, naming the class within the scope of the class has a
> special signification, and results in declaring a constructor. But
> here, we are not in a declaration (or are we, see below); in an
> expression, the name lookup finds the class name, which means that we
> have a function style cast.

No, you have an illegal constuct. The standard in 5.2 says that if
you specify Type::Type in such an instance refers to a constructor.
You can't apply () to a constructor name in an expression, so it's
illega.

>
> The reason I'm not sure is that a statement of the form:
>
> T_::T_ d ;
>
> sure looks a lot like a declaration, and adding parentheses around the
> d doesn't change anything.

It's also illegal. Same reason. T_::T_ is an unambiguous constructor
pseudonym. It is illegal to use it in a declaration like this. The
only place it is usable is to declare the constructor itself.

> It's not a legal declaration, because it
> results in declaring d twice. But according to 6.8/1, "An
> expression-statement with a function-style explicit type conversion
> [what we have here] as its leftmost subexpression can be
> indistinguishable from a declaration where the first declarator starts
> with a (. In those cases the statement is a declaration."

Huh? It doesn't declare anything.

> Calling the constructor isn't illegal. There just isn't any possible
> syntax that would do it, since the constructor can't be named.

Since there is no syntax to do it, that pretty much makes it impossible
to do. You can't call constructors. Constructors are called for you
as part of object creation.

Carl Daniel

unread,
Nov 6, 2001, 6:25:25 PM11/6/01
to

"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.0111...@posting.google.com...

I'd call it error in the compiler too - or at least a very misleading error
message.

> In this case, the first T_, of course, designates the class T_, and
> specifies the scope for the name lookup which follows. And because of
> 9/2, the scoped lookup finds the name of the class. In a declaration,
> of course, naming the class within the scope of the class has a
> special signification, and results in declaring a constructor. But
> here, we are not in a declaration (or are we, see below); in an
> expression, the name lookup finds the class name, which means that we
> have a function style cast.

I don't see how to read 12.1 (2) (" "because constructors don't have names
they are never found during name lookup") in any way that allows that to be
true. The class name is, after all, not defined within the scope of the
class. It's defined in the enclosing scope.

>
> The reason I'm not sure is that a statement of the form:
>
> T_::T_ d ;
>
> sure looks a lot like a declaration, and adding parentheses around the
> d doesn't change anything. It's not a legal declaration, because it
> results in declaring d twice. But according to 6.8/1, "An
> expression-statement with a function-style explicit type conversion
> [what we have here] as its leftmost subexpression can be
> indistinguishable from a declaration where the first declarator starts
> with a (. In those cases the statement is a declaration."

But if this is a declaration, wouldn't it be a declaration of a variable d
of type T_::T_? A type which clearly doesn't exist (and can't according to
9.2 (13)). If it were a declaration, then the following should be legal:

struct T_
{
};

void foo()
{
T_::T_(x);
}

Comeau rejects this with a much more sensible error message:

"1874.c", line 7: error: class "T_" has no member "T_"
T_::T_(x);
^

-cd

James Kanze

unread,
Nov 6, 2001, 7:41:03 PM11/6/01
to
"Carl Daniel" <cpda...@pacbell.net> wrote in message
news:<C4EF7.19281$Cf3.351...@newssvr21.news.prodigy.com>...

> "James Kanze" <ka...@gabi-soft.de> wrote in message
> news:d6651fb6.01110...@posting.google.com...
> > "RICO" <y_...@btamail.net.cn> wrote in message
> > news:<9s4r0l$ht4$1...@mail.cn99.com>...

> > > I am doubted by the code snippe:

> > As you should be.

> > > struct T_
> > > {
> > > T_(const T& t) { }
> > > };

> > > struct D_ : T_
> > > {
> > > D_() {}
> > > D_(const D& d)
> > > {
> > > T_::T_(d); // 1

> > This constructs a temporary T_, initializing it with the T_ part
> > of the parameter. It then immediately destructs the temporary,
> > without doing anything with it.

> Doesn't 12.1 (2) make this illegal?

I don't think so. 12.1/2 makes it clear that name lookup can never
find the constructor. (In fact, constructors don't have a name.) But
because of class name insertion (9.1/2), it does find the name of the
class; ::T_::T_ is exactly the same as ::T_. And 5.2.3 basically says
that the name of a type, followed by a possibly empty list of
arguments, constructs a value of the specified type. A temporary
value, of course, which will be destructed at the end of the full
expression.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --

-- Conseils en informatique oriente objet
Ziegelhttenweg 17a, 60598 Frankfurt, Germany, Tl.: +49 (0)69 19 86 27

James Kanze

unread,
Nov 7, 2001, 10:24:26 AM11/7/01
to
"Carl Daniel" <cpda...@pacbell.net> wrote in message
news:<fhZF7.10715$P%1.3824...@newssvr14.news.prodigy.com>...

What about the second sentence of 9/2: "The class-name is also
inserted into the scope of the class itself." T_::T_ refers the the
name of the class itself.

> > The reason I'm not sure is that a statement of the form:

> > T_::T_ d ;

> > sure looks a lot like a declaration, and adding parentheses around
> > the d doesn't change anything. It's not a legal declaration,
> > because it results in declaring d twice. But according to 6.8/1,
> > "An expression-statement with a function-style explicit type
> > conversion [what we have here] as its leftmost subexpression can
> > be indistinguishable from a declaration where the first declarator
> > starts with a (. In those cases the statement is a declaration."

> But if this is a declaration, wouldn't it be a declaration of a
> variable d of type T_::T_?

It is a declaration of a variable d of the type named by T_::T_.
Because of the second sentence in 9.2, the sequence T_::T_ names the
type T_.

> A type which clearly doesn't exist (and can't according to 9.2
> (13)). If it were a declaration, then the following should be
> legal:

> struct T_
> {
> };

> void foo()
> {
> T_::T_(x);
> }

> Comeau rejects this with a much more sensible error message:

> "1874.c", line 7: error: class "T_" has no member "T_"
> T_::T_(x);

Sun CC (5.0) also rejects it, with the message "T may not have a type
qualifier". Both of the versions of g++ I have access to accept it,
however. And treat it as a declaration of a variable of type T.

My interpretation of the above quoted sentence is that g++ is correct,
and the other compilers are wrong. The only thing that makes me
hesitate is that if I remember correctly, the cited passage was
suggested by Steve Adamczyk, who is also one of the authors of the EDG
front-end, so I'd expect the EDG front-end (and thus Comeau) to get it
right. (In the case of Sun, I'm willing to accept that they just
haven't gotten around to implementing name injection yet.)

Obviously, there may be text elsewhere that says that it shouldn't be
treated as a declaration, the same as there is text that says that
other contexts, T::T is the start of a definion of the constructor.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

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

John H. Spicer

unread,
Nov 7, 2001, 2:58:23 PM11/7/01
to
In article <d6651fb6.0111...@posting.google.com> ka...@gabi-soft.de

The example is somewhat mangled, but after repairing things like uses of
T and D where T_ and D_ were intended, I get the same error on both
//1 and //2.

I think James Kanze's lookup description accurately describes what the
standard says, but does not take into account some changes that have
been made by the committee since.

It turns out that there are some problematic cases (involving templates,
big surprise, huh?) that make it necessary to decide at an earlier point
in lookup whether a name refers to the constructor or to the injected
class name. This is core language issue 147.

The resolution makes the following change to 3.4.3.1 (plus a few other
changes):

If the nested-name-specifier nominates a class C, and the name
specified after the nested-name-specifier, when looked up in C, is
the injected-class-name of C (clause 9 class), the name is instead
considered to name the constructor of class C. Such a constructor
name shall only be used in the declarator-id of a constructor
definition that appears outside of the class definition.

The committee considered this a safe change because it really only affects
people who write T::T where they could have simply written T.

Also, I don't think that EDG is responsible for the idea of name injection,
but I could be wrong.

John Spicer
Edison Design Group

James Kanze

unread,
Nov 7, 2001, 2:59:13 PM11/7/01
to
Ron Natalie <r...@sensor.com> wrote in message
news:<3BE836DB...@sensor.com>...

> > Strange. I would call this an error in the compiler. A
> > constructor obviously cannot have it's address taken, of course.
> > In fact, a constructor cannot even be named, so I don't quite know
> > what kind of syntax you would need to take its address.

> Your construct is illegal.

I don't think so, and at least one compiler (g++) agrees with me.
(More importantly, of course, I have the impression that the standard
agrees with me.)

> The compiler is trying to make a guess as to what it is you are
> trying to do. Technically, all the compiler is required to generate
> is a "diagnostic" the contents of which are not specified by the
> standard.

I know. And in interpreting its error message, I'm trying to make a
guess as to what the compiler is guessing. In this case, I'm stumped.

> > In this case, the first T_, of course, designates the class T_,
> > and specifies the scope for the name lookup which follows. And
> > because of 9/2, the scoped lookup finds the name of the class. In
> > a declaration, of course, naming the class within the scope of the
> > class has a special signification, and results in declaring a
> > constructor. But here, we are not in a declaration (or are we,
> > see below); in an expression, the name lookup finds the class
> > name, which means that we have a function style cast.

> No, you have an illegal constuct. The standard in 5.2 says that if
> you specify Type::Type in such an instance refers to a constructor.
> You can't apply () to a constructor name in an expression, so it's
> illega.

Where in 5.2. There's only one sentence in 5.2 itself, "Postfix
expressions group left-to-right", and that's certainly not what you
are talking about. The expression matches one of the possible syntax
listed in 5.2: "simple-type-specifier ( expression-list )", because of
the second sentence in 9/2 "The class-name is also inserted into the
scope of the class itself." So qualified name lookup (3.4.3) finds
the second Type, and finds it to be a type name. As a result,
Type::Type is a simple-type-specifier (specifying the type Type), and
we are in 5.2.3.

> > The reason I'm not sure is that a statement of the form:

> > T_::T_ d ;

> > sure looks a lot like a declaration, and adding parentheses around
> > the d doesn't change anything.

> It's also illegal. Same reason. T_::T_ is an unambiguous
> constructor pseudonym.

There's no such thing as a constructor pseudonym. A constructor is an
unnamed function, without name or pseudonym. Certain constructions in
the language cause the compiler to invoke the constructor, but you
can't do anything with it directly. The class name followed by a
parameter list declares or defines the constructor, so T::T(d) would
fact declare or define the constructor, *IF* d were a type name.
Otherwise, I can't find a special case which would apply, so T::T
names the type T.

> It is illegal to use it in a declaration like this. The only place
> it is usable is to declare the constructor itself.

Where does it say this in the standard? The token sequence Type::Type
definitely designates the type Type, according to 9.2. A declaration
of a constructor is defined as "a special declarator syntax using an
optional function-specifier followed by the constructor's class name
*followed* *by* *a* *parameter* *list*" (12.1); since there is no
parameter list, there is no declaration or definition of a
constructor.

> > It's not a legal declaration, because it results in declaring d
> > twice. But according to 6.8/1, "An expression-statement with a
> > function-style explicit type conversion [what we have here] as its
> > leftmost subexpression can be indistinguishable from a declaration
> > where the first declarator starts with a (. In those cases the
> > statement is a declaration."

> Huh? It doesn't declare anything.

It does according the the standard and g++.

> > Calling the constructor isn't illegal. There just isn't any
> > possible syntax that would do it, since the constructor can't be
> > named.

> Since there is no syntax to do it, that pretty much makes it
> impossible to do. You can't call constructors. Constructors are
> called for you as part of object creation.

Right. More importantly, you cannot name them; T::T names the class
T. If it didn't, T::T wouldn't be the "constructor's class name", and
couldn't be used to define a constructor. (Basically, if what follows
is a parameter list, you are trying to declare or define the
constructor, but if it isn't a parameter list, then you have named the
class.)

Interestingly, although I've never seen a compiler which supports it,
according to 12.1, the following is also legal:

struct T { T() ; } ; // Define the class.

T() { std::cout << "T::T()\n" ; }
// This is the class' constructor.

In the second line, what is T() if not "the constructor's class name
followed by a parameter list?" Personally, I rather think that this
was not the intent, and maybe a defect report is in order; no one
supports it, and I rather fear that it could lead to some serious
ambiguities.

--
James Kanze mailto:ka...@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
-- Conseils en informatique orientée objet
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany, Tél.: +49 (0)69 19 86 27

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

Ron Natalie

unread,
Nov 7, 2001, 3:01:17 PM11/7/01
to

> What about the second sentence of 9/2: "The class-name is also
> inserted into the scope of the class itself."

True

> T_::T_ refers the the
> name of the class itself.

Incorrect assumption. 5.1/7 which describes how :: works specifically
says that this construct is a reference to the constructor.

Carl Daniel

unread,
Nov 7, 2001, 3:49:27 PM11/7/01
to

"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.0111...@posting.google.com...
> "Carl Daniel" <cpda...@pacbell.net> wrote in message
> news:<fhZF7.10715$P%1.3824...@newssvr14.news.prodigy.com>...
> > "James Kanze" <ka...@gabi-soft.de> wrote in message
> > news:d6651fb6.0111...@posting.google.com...
> > > "Carl Daniel" <cpda...@pacbell.net> wrote in message
> > > news:<FHzF7.19211$wq7.347...@newssvr21.news.prodigy.com>...
> > > > "RICO" <y_...@btamail.net.cn> wrote in message
> > > > news:9s4r0l$ht4$1...@mail.cn99.com...
[major snip]

> > I don't see how to read 12.1 (2) (" "because constructors don't have
> > names they are never found during name lookup") in any way that
> > allows that to be true. The class name is, after all, not defined
> > within the scope of the class. It's defined in the enclosing scope.
>
> What about the second sentence of 9/2: "The class-name is also
> inserted into the scope of the class itself." T_::T_ refers the the
> name of the class itself.
>

Got me! I missed that sentence on the first - third readings :)

>
> > But if this is a declaration, wouldn't it be a declaration of a
> > variable d of type T_::T_?
>

[snip]


>
> > Comeau rejects this with a much more sensible error message:
>
> > "1874.c", line 7: error: class "T_" has no member "T_"
> > T_::T_(x);
>
> Sun CC (5.0) also rejects it, with the message "T may not have a type
> qualifier". Both of the versions of g++ I have access to accept it,
> however. And treat it as a declaration of a variable of type T.
>
> My interpretation of the above quoted sentence is that g++ is correct,
> and the other compilers are wrong. The only thing that makes me
> hesitate is that if I remember correctly, the cited passage was
> suggested by Steve Adamczyk, who is also one of the authors of the EDG
> front-end, so I'd expect the EDG front-end (and thus Comeau) to get it
> right. (In the case of Sun, I'm willing to accept that they just
> haven't gotten around to implementing name injection yet.)
>
> Obviously, there may be text elsewhere that says that it shouldn't be
> treated as a declaration, the same as there is text that says that
> other contexts, T::T is the start of a definion of the constructor.
>

Definitely a dark corner at best. Thanks for the enlightenment!

-cd

Homer Meyer

unread,
Nov 7, 2001, 6:34:16 PM11/7/01
to
"James Kanze" <ka...@gabi-soft.de> wrote in message
news:d6651fb6.0111...@posting.google.com...
> Interestingly, although I've never seen a compiler which supports it,
> according to 12.1, the following is also legal:
>
> struct T { T() ; } ; // Define the class.
>
> T() { std::cout << "T::T()\n" ; }
> // This is the class' constructor.
>
> In the second line, what is T() if not "the constructor's class name
> followed by a parameter list?" Personally, I rather think that this
> was not the intent, and maybe a defect report is in order; no one
> supports it, and I rather fear that it could lead to some serious
> ambiguities.

I think that's already illegal according to 8.3/1.

"A declarator-id shall not be qualified except for the definition of a
member function (9.3), or static data member (9.4) or nested class (9.7)
outside of its class, ...."

meaning that in the case of member functions (constructors are member
functions) that the declarator-id, "T" in the example above, must be
qualified.

Anthony Williams

unread,
Nov 8, 2001, 8:00:19 AM11/8/01
to
"Ron Natalie" <r...@sensor.com> wrote in message
news:3BE9580C...@sensor.com...

> > T_::T_ refers the the
> > name of the class itself.
>
> Incorrect assumption. 5.1/7 which describes how :: works specifically
> says that this construct is a reference to the constructor.

Ouch.

5.1p7:

"... Where classname::classname is used, and the two classnames refer to the
same class, this notation names the constructor (12.1). ..."

12.1p1:

"Constructors do not have names...."

12.1p2:

"...Because constructors do not have names, they are never found during name
lookup;..."

Surely this is an inconsistency?

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer

Reply all
Reply to author
Forward
0 new messages