Typedef of inaccessible type

Discussion in 'C++' started by ales.pergl@gmail.com, Jan 13, 2012.

  1. Guest

    When I have multiple nested classes, I find it unnecessarily verbose to spell out the fully qualified name of the most nested class when defining its members.
    So I'm looking for a way to define an alias for the fully qualified class name. Like this:

    // in header
    class A {
    class B {
    class C {
    void DoStuff();
    };
    };
    };

    // in cpp
    typedef A::B::C C; // error, A::B::C is inacessible in this context

    void C::DoStuff() {} // would love to be able to shorten the class name

    The problem is, the above doesn't compile, because C is not accessible from global scope. The easiest workaround is to define a macro instead of a typedef:

    #define C A::B::C

    Does anybody know of a better way, without using the preprocessor?

    Thanks.
     
    , Jan 13, 2012
    #1
    1. Advertising

  2. On 13.01.2012 13:48, wrote:
    > When I have multiple nested classes, I find it unnecessarily verbose to spell out the fully qualified name of the most nested class when defining its members.
    > So I'm looking for a way to define an alias for the fully qualified class name. Like this:
    >
    > // in header
    > class A {
    > class B {
    > class C {
    > void DoStuff();
    > };
    > };
    > };


    You can always replace nested classes with friendships etc.

    I suggest you try that.

    To see what the above really means.


    > // in cpp
    > typedef A::B::C C; // error, A::B::C is inacessible in this context


    But if you make it accessible in some way, then you would be breaking
    the rules you have elaborately set up with the class nesting.


    > void C::DoStuff() {} // would love to be able to shorten the class name
    >
    > The problem is, the above doesn't compile, because C is not accessible from
    > global scope. The easiest workaround is to define a macro instead of a typedef:
    >
    > #define C A::B::C
    >
    > Does anybody know of a better way, without using the preprocessor?


    You can always confer friendship to some class that can then provide
    typedefs.

    But then you would be exposing what you have gone to pains to make
    inacessible.

    There's nothing wrong with using the preprocessor in a sensible way,
    like in your case, with the effect confined within a separately compiled
    file.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 13, 2012
    #2
    1. Advertising

  3. On 13 tammi, 14:48, wrote:
    > When I have multiple nested classes, I find it unnecessarily verbose to spell out the fully qualified name of the most nested class when defining its members.
    > So I'm looking for a way to define an alias for the fully qualified classname. Like this:
    >
    >   // in header
    >   class A {
    >     class B {
    >       class C {
    >         void DoStuff();
    >       };
    >     };
    >   };
    >
    >   // in cpp
    >   typedef A::B::C C;   // error, A::B::C is inacessible in this context
    >
    >   void C::DoStuff() {} // would love to be able to shorten the class name
    >
    > The problem is, the above doesn't compile, because C is not accessible from global scope. The easiest workaround is to define a macro instead of a typedef:
    >
    >   #define C A::B::C
    >
    > Does anybody know of a better way, without using the preprocessor?
    >
    > Thanks.



    The class default visibility is private, so the classes B and C are
    not accessible from out side, even if you give the fully qualified
    name. So define the classes in public visibility and the typedef
    works. And DO NOT use a define like that! That will replace all
    occurances of capital C with the given string and cause all kinds of
    hard to understand errors.
     
    Markku Linnoskivi, Jan 13, 2012
    #3
  4. Guest

    > int main()
    > {
    > C::DoStuff();
    > }


    I am not trying to call DoStuff() from the outside. It is intentionally private to the C class. I just want to make the function definition (i.e. implementation) less verbose.
     
    , Jan 13, 2012
    #4
  5. On 13.01.2012 15:38, Leigh Johnston wrote:
    > On 13/01/2012 14:32, Leigh Johnston wrote:
    >> On 13/01/2012 12:48, wrote:
    >>> When I have multiple nested classes, I find it unnecessarily verbose
    >>> to spell out the fully qualified name of the most nested class when
    >>> defining its members.
    >>> So I'm looking for a way to define an alias for the fully qualified
    >>> class name. Like this:
    >>>
    >>> // in header
    >>> class A {
    >>> class B {
    >>> class C {
    >>> void DoStuff();
    >>> };
    >>> };
    >>> };
    >>>
    >>> // in cpp
    >>> typedef A::B::C C; // error, A::B::C is inacessible in this context
    >>>
    >>> void C::DoStuff() {} // would love to be able to shorten the class name
    >>>
    >>> The problem is, the above doesn't compile, because C is not accessible
    >>> from global scope. The easiest workaround is to define a macro instead
    >>> of a typedef:
    >>>
    >>> #define C A::B::C
    >>>
    >>> Does anybody know of a better way, without using the preprocessor?

    >>
    >> class A
    >> {
    >> class B
    >> {
    >> class C
    >> {
    >> public:
    >> static void DoStuff() {}
    >> };
    >> public:
    >> typedef C nested_type;
    >> };
    >> public:
    >> typedef B::nested_type nested_type;
    >> };
    >>
    >> typedef A::nested_type C;
    >>
    >> int main()
    >> {
    >> C::DoStuff();
    >> }
    >>

    >
    > My answer should have been:
    >
    > class A
    > {
    > class B
    > {
    > class C
    > {
    > public:
    > void DoStuff();
    > };
    > public:
    > typedef C nested_type;
    > };
    > public:
    > typedef B::nested_type nested_type;
    > };
    >
    > typedef A::nested_type C;
    >
    > void C::DoStuff()
    > {
    > }
    >
    > int main()
    > {
    > }


    Tip: if you select all the text in Thunderbird (e.g. via [Ctrl A])
    before hitting "Reply", then it seems to preserve indents.

    Anyway, the above ends up first making classes inaccessible, possibly
    for some good reason, and then making them accessible via the typedefs.

    Instead they could just have been made public in the first place.

    An alternative is to use a namespace like `detail` (a convention used in
    Boost), and define a class there that can provide typedefs. It still
    technically exposes the classes that should be inaccessible, but
    provides a marginal measure of protection via Python-like convention.
    The point is after all not to protect against a determined hacker, but
    to protect against inadvertent usage.

    I tried to explain this in my original answer in this thread.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Jan 13, 2012
    #5
  6. Guest

    > But if you make it accessible in some way, then you would be breaking
    > the rules you have elaborately set up with the class nesting.


    Naturally, I want to expose the type names only to the limited scope of the .cpp file where member definitions reside. So I'm not trying to void my elaborate privilege setup. ;)

    > You can always confer friendship to some class that can then provide
    > typedefs.


    I could do that, but that would require me to put in the header file what are essentially implementation details of the classes. Furthermore, it would not bring many benefits with regard to code verbosity/readability.

    > But then you would be exposing what you have gone to pains to make
    > inacessible.


    .... but only to the friendly class, which would be OK. But again, it wouldn't be less verbose nor more readable.

    > There's nothing wrong with using the preprocessor in a sensible way,
    > like in your case, with the effect confined within a separately compiled
    > file.


    I agree.
     
    , Jan 13, 2012
    #6
  7. On 13.01.2012 16:00, wrote:
    >> But if you make it accessible in some way, then you would be breaking
    >> the rules you have elaborately set up with the class nesting.

    >
    > Naturally, I want to expose the type names only to the limited scope of the .cpp file where member definitions reside. So I'm not trying to void my elaborate privilege setup. ;)
    >
    >> You can always confer friendship to some class that can then provide
    >> typedefs.

    >
    > I could do that, but that would require me to put in the header file what are essentially implementation details of the classes. Furthermore, it would not bring many benefits with regard to code verbosity/readability.
    >
    >> But then you would be exposing what you have gone to pains to make
    >> inacessible.

    >
    > ... but only to the friendly class, which would be OK. But again, it wouldn't
    > be less verbose nor more readable.


    I'm sorry, I'm too much accustomed to pure header modules.

    In your case, with separate compilation, it is "the" solution.

    <code>
    class ClassA
    {
    friend class Class;

    class ClassB
    {
    friend class Class;

    class ClassC
    {
    public:
    void doStuff();
    };
    };
    };


    // In implementation file:
    struct Class { typedef ClassA::ClassB::ClassC C; };
    typedef Class N;

    void N::C::doStuff() {}
    </code>


    >
    >> There's nothing wrong with using the preprocessor in a sensible way,
    >> like in your case, with the effect confined within a separately compiled
    >> file.

    >
    > I agree.


    I think if I had to do this, if it was a requirement to have such nested
    classes, then I'd use the preprocessor to simplify the implementation.

    But typedef'ing works also, as shown above.

    Well, except for constructors and destructors. There, the macro approach
    really has the edge. ;-)


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 13, 2012
    #7
  8. On 1/13/2012 9:09 AM, Markku Linnoskivi wrote:
    > On 13 tammi, 14:48, wrote:
    >> When I have multiple nested classes, I find it unnecessarily verbose to spell out the fully qualified name of the most nested class when defining its members.
    >> So I'm looking for a way to define an alias for the fully qualified class name. Like this:
    >>
    >> // in header
    >> class A {
    >> class B {
    >> class C {
    >> void DoStuff();
    >> };
    >> };
    >> };
    >>
    >> // in cpp
    >> typedef A::B::C C; // error, A::B::C is inacessible in this context
    >>
    >> void C::DoStuff() {} // would love to be able to shorten the class name
    >>
    >> The problem is, the above doesn't compile, because C is not accessible from global scope. The easiest workaround is to define a macro instead of a typedef:
    >>
    >> #define C A::B::C
    >>
    >> Does anybody know of a better way, without using the preprocessor?
    >>
    >> Thanks.

    >
    >
    > The class default visibility is private, so the classes B and C are
    > not accessible from out side, even if you give the fully qualified
    > name. So define the classes in public visibility and the typedef
    > works. And DO NOT use a define like that! That will replace all
    > occurances of capital C


    No, only occurrences where C is a complete token. For instance, in the
    token Class, the 'C' is not going to be replaced to yield A::B::Class.

    > with the given string and cause all kinds of
    > hard to understand errors.


    I am fairly certain that the OP doesn't have real classes named A, B and
    C...

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 13, 2012
    #8
  9. Guest

    >
    > class ClassA
    > {
    > friend class Class;
    >
    > class ClassB
    > {
    > friend class Class;
    >
    > class ClassC
    > {
    > public:
    > void doStuff();
    > };
    > };
    > };
    >


    Interestingly enough, this has its own issues. With this approach, ClassA (and ClassB) is blindly giving friendship to any class Class. I'm not entirely sure what the standard says about this, but I've tested with VC10 that if I include this class declaration in two different modules where each defines its own class Class, the linker doesn't complain about any naming issues and both "Class"es joyfully access ClassA's private members. Possibly it's because as long as class Class is fully defined and kept private to a module, there's no ambiguity from the linker's point of view.

    Seems to me that macros really win this one, hands down. :)
     
    , Jan 16, 2012
    #9
  10. Joe keane Guest

    In article <2860857.953.1326466829576.JavaMail.geo-discussion-forums@vbtv21>,
    <> wrote:
    >I could do that, but that would require me to put in the header file
    >what are essentially implementation details of the classes. Furthermore,
    >it would not bring many benefits with regard to code
    >verbosity/readability.


    You can also create *two* header files, one for all the clients of your
    classes, and one that's only included by your implementation file(s).
     
    Joe keane, Jan 16, 2012
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jason Shohet
    Replies:
    1
    Views:
    484
    William F. Robertson, Jr.
    Aug 1, 2003
  2. Manfred Braun
    Replies:
    3
    Views:
    770
    Manfred Braun
    Aug 30, 2003
  3. Jeremy S.
    Replies:
    6
    Views:
    506
    Jeremy S.
    Jan 22, 2005
  4. Shane
    Replies:
    0
    Views:
    376
    Shane
    Oct 14, 2007
  5. oor
    Replies:
    0
    Views:
    1,358
Loading...

Share This Page