static member data + private c'tor

static member data + private c'tor

Post by Dhru » Sat, 02 Aug 2003 10:04:23




> Consider:

> struct X
> {
>     static X x;
> private:
>     X() { }
> };

> X::X x;

> int main() { }

> Is this legal code?  Why or why not?  gcc-3.3 says that X::X() is
> private, but it seems to me that it should be accessible, since x
> is declared (and defined?) within the scope of X.  Comeau online
> says that 'overloaded function "X::X" is not a type name', so it
> apparently doesn't even get to the issue of access, since it
> doesn't even recognize the construction.  This is not an academic
> question.  I was trying to create a singleton which, for legacy
> reasons, could not be a function (so I couldn't use a Meyers
> singleton).

This isn't legal because There is nothing like X within X, you cannot have
anything like it.

The correct way would be:

X::x = something;
OR:
something = X::x;

Regards,
-Dhruv.

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

 
 
 

static member data + private c'tor

Post by Richard Smit » Sat, 02 Aug 2003 10:06:45



>  > struct X
>  > {
>  >     static X x;
>  > private:
>  >     X() { }
>  > };

>  > X::X x;
>  > Is this legal code? Why or why not?

> It isn't:
> A class can't contain itself as a member!

Not quite correct: a class can't contain itself as a
*non-static* data member.  This is a static data member
which is perfectly legal.

Quote:> otherwise you could write:

> X x;       // construction - doesn't matter how...
> x;         // access the object
> x.x;       // access the member of the object
> x.x.x;     // access the member of the member of the object
> x.x.x.x;   // access the member of the member of ....

And this is all perfectly valid, if slightly bizarre.

Quote:> You can't access a private constructor.

Yes you can.  X::x is a member of X and so can access the
private constructor.  Even if I write

  X X::x = X();

this is is legal as the access checking happens within the
context of X.

Quote:> If you declare a constructor private you prevent the compiler from
> creating a default (public) constructor and inhibit the access -
> therefore you never need to define it (except for the case of in-place
> creation in a member function...)

You only inhibit access by non-members.  This is access by a
member (specifically a static data member's initialiser) and
thus the constructor must be defined.

The only problem with this code was the one that others have
already pointed out: namely that X::X x should have been
writen X X::x.

--
Richard Smith

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

 
 
 

static member data + private c'tor

Post by Yuval Hofs » Sat, 02 Aug 2003 10:07:24



Quote:> Consider:

> struct X
> {
>     static X x;
> private:
>     X() { }
> };

> X::X x;

> int main() { }

Hi,

Did you mean:

struct X
{
    static X x;
public:
    void foo() {};

private:
    X() {}

Quote:};

X X::x;

int main(int argc, char * argv[])
{      
        X::x.foo();
        ...
        return something;

Quote:}

Yuval.

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

 
 
 

static member data + private c'tor

Post by Joshua Lehr » Sat, 02 Aug 2003 17:27:03


 > It isn't:
 > A class can't contain itself as a member!
 > otherwise you could write:
 >
 > X x;       // construction - doesn't matter how...
 > x;         // access the object
 > x.x;       // access the member of the object
 > x.x.x;     // access the member of the member of the object
 > x.x.x.x;   // access the member of the member of ....
 >

sure it can:

struct X {
  X(X& x2) : x(x2) { }
  X& x;

Quote:};

X x(x);
x==x.x;
x.x==x.x.x;
x==x.x.x;

:)

joshua lehrer
factset research systems
NYSE:FDS

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

 
 
 

static member data + private c'tor

Post by llewell » Sat, 02 Aug 2003 17:30:24




 >>Consider:
 >>
 >>struct X
 >>{
 >>    static X x;
 >>private:
 >>    X() { }
 >>};
 >>
 >>X::X x;
 >
 > Well that is certainly an error because there is no nested type X within
 > either a class(or struct) or namespace called X.

Not true. See 9/2. X is itself nested within X.

 >
 > try writing:
 >
 > X X::x;

However this is what the OP most probably wants.

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

 
 
 

static member data + private c'tor

Post by llewell » Sun, 03 Aug 2003 01:13:37





>> Consider:

>> struct X
>> {
>>     static X x;
>> private:
>>     X() { }
>> };

>> X::X x;

> What is this line supposed to mean?  There is no type X::X.

I would like to know why so many people say there is no type X::X
    . 9/2 makes me think X::X is a type, and is the same type as X:

#    A class name is inserted into the scope in which it is declared
#    immediately after the class-name is seen. *The class-name is also
#    inserted into the scope of the class itself.* For purposes of access
#    checking, the inserted class-name is treated as if it were a public
#    member name. A class-specifier is commonly reffered to as a class
#    definition. A class is considered defined after the closing brace of
#    its class-specifier has been seen even though its member functions are
#    in general not yet defined.

(Emphasis mine.)

(There are 2 issues, 175 and 176, on class-name injection, but as far
    as I can tell they do not affect the issue of whether X::X is a
    type. )

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

 
 
 

static member data + private c'tor

Post by Dhru » Sun, 03 Aug 2003 02:09:18




>> Consider:

>> struct X
>> {
>>     static X x;
>> private:
>>     X() { }
>> };

>> X::X x;

>> int main() { }

[snip]......

Quote:

> This isn't legal because There is nothing like X within X, you cannot have
> anything like it.

> The correct way would be:

> X::x = something;
> OR:
> something = X::x;

Oops, I thought that X::X x was written in main. Ok, yes, as the others
have pointed out, it should be X::X x.

Regards,
-Dhruv.

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

 
 
 

static member data + private c'tor

Post by Gabriel Dos Rei » Sun, 03 Aug 2003 17:42:49



| Consider:
|
| struct X
| {
|     static X x;
| private:
|     X() { }
| };
|
| X::X x;
|
| int main() { }
|
| Is this legal code?  Why or why not?  gcc-3.3 says that X::X() is
| private, but it seems to me that it should be accessible, since x
| is declared (and defined?) within the scope of X.  Comeau online
| says that 'overloaded function "X::X" is not a type name', so it
| apparently doesn't even get to the issue of access, since it
| doesn't even recognize the construction.  This is not an academic
| question.  I was trying to create a singleton which, for legacy
| reasons, could not be a function (so I couldn't use a Meyers
| singleton).

What you probably wanted is

    X X::x;

as many have already pointed out.

However, the code snippet you presented is interesting in that it
exposes torny issues and differences in the standards implemented by
both compilers.

The fundamental issue is to assert on the well-formed-ness of the
following putative simple-declaration (at the global scope).

    X::X x;

That will be a simple-declaration if the sequence of tokens
'X :: X' designates a type.  Fire up a qualified-name lookup.
That name lookup finds the second 'X' to be the famous injected
class-name.  The magic known as "class name injection" is described by
the Holy Standard text as follows:

   9/2
     [...] The class-name is also inserted into the scope of the class
     itself.

That magic is supposed to solve many issues (to be found elsewhere).
However, that magic has some dark corners.  For example, what does the
injected class-name refer to?

If, like GCC, one assumes that the injected class-name refers to the
type then the outcome of the qualified-name lookup for 'X :: X' is 'X'.
So one has a simple-declaration -- which is also a definition for 'x'.
Then one goes on doing the usual semantics checking for the
constructor, which is inaccessible in this context.  That explains
the diagnostic message from GCC.

On the other hand, if

   * one is aware of the class name injection magic and of some of its
     dark corners, e.g.

     Core Issue #147
     http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#147
     now part of C++2003

     Core Issue #175
     http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#175
     which is in a DR status (and part of the current Working Paper)

   * and one has read the paper

      http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/1999/n1187.pdf

    (written by one of the member of the team that sells the front-end
     used by Comeau)

then one concludes that 'X :: X' designates the constructor for
class X. (What?  Someone told you constructors don't have names?)

Hence the putative simple-declaration is ill-formed and one
understands the diagnostic message given by como.

I leave it to the interested reader to elaborate on what happens if
one slightly changes

    X X::x;

to

   ::X ::X::x;

[that amuses me because I've been seeing recent trend in putting '::' in
front of everything :-)]

The interested reader might further look at

    struct foo {
       foo bar();
    };

    // ...

    namespace {
      typedef int foo;
    }

   ::foo ::foo::bar() { /* ... */ }

--

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

 
 
 

static member data + private c'tor

Post by Gabriel Dos Rei » Sun, 03 Aug 2003 17:45:29



|


|  >>Consider:
|  >>
|  >>struct X
|  >>{
|  >>    static X x;
|  >>private:
|  >>    X() { }
|  >>};
|  >>
|  >>X::X x;
|  >
|  > Well that is certainly an error because there is no nested type X within
|  > either a class(or struct) or namespace called X.
|
| Not true. See 9/2. X is itself nested within X.

Yes, but you need an upgrade

   http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#176

:-)

--

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

 
 
 

static member data + private c'tor

Post by Gabriel Dos Rei » Sun, 03 Aug 2003 17:57:30


|


| >
| >> Consider:
| >
| >> struct X
| >> {
| >>     static X x;
| >> private:
| >>     X() { }
| >> };
| >
| >> X::X x;
| >
| > What is this line supposed to mean?  There is no type X::X.

Well, before there were clarification, X::X was treated as X -- which
means you can repeat the '::X' part as you like.

| I would like to know why so many people say there is no type X::X
|     . 9/2 makes me think X::X is a type, and is the same type as X:

The C++98 wording isn't very clear.  It says that the class-name 'X'
is inserted in the scope of X, but it does not say exactly what that
name is supposed to refer to.

| #    A class name is inserted into the scope in which it is declared
| #    immediately after the class-name is seen. *The class-name is also
| #    inserted into the scope of the class itself.* For purposes of access
| #    checking, the inserted class-name is treated as if it were a public
| #    member name. A class-specifier is commonly reffered to as a class
| #    definition. A class is considered defined after the closing brace of
| #    its class-specifier has been seen even though its member functions are
| #    in general not yet defined.
|
| (Emphasis mine.)
|
| (There are 2 issues, 175 and 176, on class-name injection, but as far
|     as I can tell they do not affect the issue of whether X::X is a
|     type. )

There is another issue (which is part of TC1, i.e. part of C++2003).

   http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#147

which rules that X::X names a constructor.

--

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

 
 
 

static member data + private c'tor

Post by Andy Sawye » Mon, 04 Aug 2003 07:22:23



 on 1 Aug 2003 13:09:18 -0400,


>> something = X::x;

> Oops, I thought that X::X x was written in main. Ok, yes, as the others
> have pointed out, it should be X::X x.

I think you'll find that what others have (correctly) pointed out is
that is should be:

X X::x;

Regards,
 Andy S
--
"Light thinks it travels faster than anything but it is wrong. No matter
 how fast light travels it finds the darkness has always got there first,
 and is waiting for it."                  -- Terry Pratchett, Reaper Man

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

 
 
 

static member data + private c'tor

Post by llewell » Mon, 04 Aug 2003 11:09:36





> |


> | >
> | >> Consider:
> | >
> | >> struct X
> | >> {
> | >>     static X x;
> | >> private:
> | >>     X() { }
> | >> };
> | >
> | >> X::X x;
> | >
> | > What is this line supposed to mean?  There is no type X::X.

> Well, before there were clarification, X::X was treated as X -- which
> means you can repeat the '::X' part as you like.

> | I would like to know why so many people say there is no type X::X
> |     . 9/2 makes me think X::X is a type, and is the same type as X:

> The C++98 wording isn't very clear.  It says that the class-name 'X'
> is inserted in the scope of X, but it does not say exactly what that
> name is supposed to refer to.

> | #    A class name is inserted into the scope in which it is declared
> | #    immediately after the class-name is seen. *The class-name is also
> | #    inserted into the scope of the class itself.* For purposes of access
> | #    checking, the inserted class-name is treated as if it were a public
> | #    member name. A class-specifier is commonly reffered to as a class
> | #    definition. A class is considered defined after the closing brace of
> | #    its class-specifier has been seen even though its member functions are
> | #    in general not yet defined.
> |
> | (Emphasis mine.)
> |
> | (There are 2 issues, 175 and 176, on class-name injection, but as far
> |     as I can tell they do not affect the issue of whether X::X is a
> |     type. )

> There is another issue (which is part of TC1, i.e. part of C++2003).

>    http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#147

> which rules that X::X names a constructor.

[snip]

Thank you. I missed this one because I only checked the index
    by section, and in that listing it shows under 5.1 (where I did
    not look) as apposed to clause 9 (where I did look.) So now I know
    X::X x is ill-formed (in C++2003).

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