JVApen
JVApen

Reputation: 11317

How to get the number of members in a class at compile time

I often encounter situations where I have to implement custom copy/move constructors. However some time later, it occurs that the class gets extended with a new member and this custom copy/move constructor is not updated, so I'm searching for a way to prevent the code from compiling without updating these methods.

Header code:

class MyClass
   {
   public:
       MyClass(const MyClass &rhs);
       // ...
   private:
       std::string                 _s;
       std::unique_ptr<OtherClass> _owned;
       bool                        _b;
   };

Cpp code:

MyClass::MyClass(const MyClass &rhs)
    : _s(rhs._s)
    , _b(rhs._b)
    {
    if (rhs._owned)
       _owned = rhs._owned->clone();
    }

So, if I add some member to MyClass, example: std::size_t _size; than I would like a compilation error for the copy constructor.

My current solution is to add:

static_assert(sizeof(MyClass) == 32, "...");

near this implementation of the copy constructor. All of this works fine, unfortunately this only works when the size of the class increases. So if I instead add bool _b2; all compiles unfortunately.

So instead of checking the size, I would like to check the number of members. Unfortunately I haven't found this yet. Are there any suggestions?

I've already considered:

All these ideas however need code/guideline changes, so ideally I would just like to write static_assert(number_of_members<MyClass>::value == 3, "...");, any ideas?

Upvotes: 5

Views: 682

Answers (2)

NickLamp
NickLamp

Reputation: 862

C++ does not have reflection built in. However, you can try using an external library xCppRefl which should provide reflection (Never used it before and it's quite old so let me know if using the library works for you).

Stepping through the source if you do

std::vector<DataMember> dataMembers = className.getDataMembers();

And then run assert(dataMembers.size() == expectedNumMembers) you should be able to test if the number of members in a class is what you expect.

Upvotes: -1

Barry
Barry

Reputation: 302738

Rule of Zero:

Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership (which follows from the Single Responsibility Principle). Other classes should not have custom destructors, copy/move constructors or copy/move assignment operators.

In this case, if you simply had a:

template <class T>
struct clone_unique_ptr {
    std::unique_ptr<T> p;

    clone_unique_ptr(const clone_unique_ptr& rhs)
    : p(rhs.p ? rhs.p->clone() : nullptr)
    { }

    // rest of special members
};

Then you wouldn't have to write anything special:

class MyClass
{
public:
    MyClass(const MyClass&) = default;
private:
   std::string                  _s;
   clone_unique_ptr<OtherClass> _owned;
   bool                         _b;
};

Upvotes: 6

Related Questions