简体   繁体   中英

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:

  • banning bool in favor of short , though it breaks all sense of intention.
  • replacing bool by bitset, however different values can't have different names
  • Put all default copyable members in separate struct, which introduces complexity
  • Add static const auto with number of members to the class, hoping this gets updated on adding a member

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?

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;
};

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM