6

I currently have two unnamed classes defined in my Foo.h:

class Foo {
public:
    Foo();

    class {
    private:
        int x;
        int y;
    public:
        int GetX() { return x; }
        int GetY() { return y; }
    } Sub1;

    class {
    private:
        int x;
    public:
        int GetX() { return x; }
    } Sub2;
}

This code compiles just fine, and it used like this:

 Foo temp;
 int Ax, Ay, Bx;
 Ax = temp.Sub1.GetX();
 Ay = temp.Sub1.GetY();
 Bx = temp.Sub2.GetX();

However, now I want to move the member function definitions to the source file.The only way I know to split this class into a header file and source file, is to name the classes:

Foo.h:

class Foo {

private:    
    class A {
    private:
        int x;
        int y;
    public:
        int GetX();
        int GetY();
    };

    class B {
    private:
        int x;
    public:
        int GetX();
    };

public:
    Foo();
    A Sub1;
    B Sub2;

}

Foo.cpp:

int Foo::A::GetX() { return x; }
int Foo::A::GetY() { return y; }
int Foo::B::GetX() { return x; }

This code is not what I want, however, since it is ugly and I didn't want a named class in the first place.

Is it possible to split the class into a header file and source file? Or is this just bad code design?

jvpernis
  • 195
  • 8
  • Consider using structs if Sub1 and Sub2 are just going to be data members of Foo. Then you could remove the need for Get functions as well. – timato May 20 '15 at 15:35
  • 1
    If your internal classes become more than ``struct``s, you might consider moving them out of the class and into a private ``namespace``. – Ami Tavory May 20 '15 at 15:36
  • If you use the unnamed inner classes, how does the compiler know which `GetX` function to use? You can't refer by class name, since there aren't any. – Thomas Matthews May 20 '15 at 16:07
  • The actual code was simplified for the purpose of demonstrating my problem, the internal classes are more than 'just' data members of Foo. – jvpernis May 21 '15 at 06:48
  • @AmiTavory A private namespace sounds interesting.. Do you have more information about that? – jvpernis May 21 '15 at 06:56

2 Answers2

3

It is, unfortunately, impossible. §9.3/5:

If the definition of a member function is lexically outside its class definition, the member function name shall be qualified by its class name using the :: operator.

Since no class name exists, no out-of-class definitions for member functions are possible. The fact that GCC allows decltype-specifiers in this context is a bug.

Columbo
  • 60,038
  • 8
  • 155
  • 203
0

With gcc at least, you can do the trick using decltype:

int decltype(Foo::Sub1)::GetX() { return x; }

It is not standards compliant, though, as Columbo has already pointed out. So don't blame me, if a future version of gcc refuses to compile this. But we all now, that gcc has never been dogmatic about standards compliance, and that the gcc team has a strong tendency to keep language extensions, if they are both unambigous (which is clearly the case here) and useful to at least some programmers. Over the time, many of these gcc extensions have eventually become part of the standards.

Nonetheless, clang and probably most other compilers refuse this construct with the error message:

'decltype' cannot be used to name a declaration

But even clang can be tricked into accepting the decltype trick. We just need to do a typedef:

typedef decltype(Foo::Sub1) Sub1type;
int Sub1type::GetX() { return x; }

Of course, this is not much different to naming the unnamed classes. The advantage of the typedef solution might still be, that you can hide away the type names inside a private namespace.

Kai Petzke
  • 2,150
  • 21
  • 29