Typedef of inaccessible type

A

ales.pergl

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.
 
A

Alf P. Steinbach

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
 
M

Markku Linnoskivi

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.
 
A

ales.pergl

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.
 
A

Alf P. Steinbach

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
 
A

ales.pergl

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.
 
A

Alf P. Steinbach

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. ;)


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 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() {}

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
 
V

Victor Bazarov

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
 
A

ales.pergl

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. :)
 
J

Joe keane

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).
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top