1
votes

Are there any good methods of separating a nested data type definition from the container and into another file?

I have a class with multiple nested structs/class enums defined within a header which can be quite long.

MyClass.h

#ifndef MYCLASS_H_
#define MYCLASS_H_
#include <stdint.h>

namespace my_namespace{

class MyClass {

public:

  enum class NestedEnumClass {
    VALUE1, VALUE2, VALUE3
  };

  struct NestedStruct {
    float a;
    float b;
    uint_fast16_t c;
  };

  struct SomeOtherNestedStruct {
    float a;
    float b;
    uint_fast16_t c;
  };

  struct AnotherNestedStruct {
    float a;
    float b;
    uint_fast16_t c;
  };

private:
  struct CombinedStruct {
    NestedStruct a;
    NestedStruct b;
    NestedStruct c;
    AnotherNestedStruct d;
    NestedEnumClass e;
  };

  uint8_t pin;
  CombinedStruct data_;

public:
  MyClass();
  NestedEnumClass someMethod(NestedStruct nestedStruct);

}; // MyClass class.

} // my_namespace namespace.

#endif /* MYCLASS_H_ */

In order to make the header shorter/neater, I was initially thinking of forward declaring the data types in the MyClass definition header file and defining the data types in a separate source that includes the header file.

However, the compiler rightly complains about an incomplete type when I try to instantiate any of the data types.

I suppose I could include it in-line, but it seems horrible:
MyClass_DataTypes.inc

public:
enum class NestedEnumClass {
    VALUE1, VALUE2, VALUE3
  };

struct NestedStruct{
  float a;
  float b;
  uint_fast16_t c;
};

struct SomeOtherNestedStruct {
  float a;
  float b;
  uint_fast16_t c;
};

struct AnotherNestedStruct {
    float a;
    float b;
    uint_fast16_t c;
  };

private:
struct CombinedStruct {
  NestedStruct a;
  NestedStruct b;
  NestedStruct c;
  AnotherNestedStruct d;
  NestedEnumClass e;
};

Modified MyClass.h

#ifndef MYCLASS_H_
#define MYCLASS_H_
#include <stdint.h>

namespace my_namespace{

class MyClass {

#include "MyClass_DataTypes.inc" // In-line include.

private:
  uint8_t pin;
  CombinedStruct data_;

public:
  MyClass(){};
  NestedEnumClass someMethod(NestedStruct nestedStruct);

}; // MyClass class.

} // my_namespace namespace.

#endif /* MYCLASS_H_ */

Also, my IDE (Eclipse) is not clever enough to find look at the include for on the fly code checking, so I would need to forward declare them in the class definition even though it compiles just fine without them.

1
IMHO this is a horrible solution - Richard Hodges
@RichardHodges Do you mean separating the definition from the declaration? - matt.baker
Nested class is a strong indication that those classes should be private. Otherwise they don't need to be nested. - user3528438
No, I mean injecting code into the declaration. When those inner classes start to need member function implementations it's going to be a mess. - Richard Hodges
I'm not sure how common it is to have extensive nested type definitions (not data members) like in your example. I think the issue is that you over-stretch the namespace aspect of a class (a class is, among other things, also a namespace). My solution (or, if you want, workaround) would be to declare the member types outside of MyClass, but, of course, inside a special namespace. That allows you to spread them over as many header files as you see fit, which can nicely be included on top of files, for example MyClass.h. - Peter - Reinstate Monica

1 Answers

3
votes

Here's how I would probably approach it.

Synopsis:

  1. create another namespace for the inner classes

  2. import the names of the inner classes into my outer class's interface as needed

Something like this:

#ifndef MYCLASS_IMPL_H_
#define MYCLASS_IMPL_H_

#include <cstdint>

namespace my_namespace {
    namespace MyClassImpl {

        enum class NestedEnumClass {
            VALUE1, VALUE2, VALUE3
        };

        struct NestedStruct {
            float a;
            float b;
            uint_fast16_t c;
        };

        struct SomeOtherNestedStruct {
            float a;
            float b;
            uint_fast16_t c;
        };

        struct AnotherNestedStruct {
            float a;
            float b;
            uint_fast16_t c;
        };

    }
}
#endif

#ifndef MYCLASS_H_
#define MYCLASS_H_
#include <stdint.h>

namespace my_namespace{

    class MyClass {

    public:
        using NestedEnumClass = MyClassImpl::NestedEnumClass;
        using NestedStruct = MyClassImpl::NestedStruct;
        using SomeOtherNestedStruct = MyClassImpl::SomeOtherNestedStruct;
        using AnotherNestedStruct = MyClassImpl::AnotherNestedStruct;


    private:
        struct CombinedStruct {
            NestedStruct a;
            NestedStruct b;
            NestedStruct c;
            AnotherNestedStruct d;
            NestedEnumClass e;
        };

        uint8_t pin;
        CombinedStruct data_;

    public:
        MyClass();
        NestedEnumClass someMethod(NestedStruct nestedStruct);

    }; // MyClass class.

} // my_namespace namespace.