Reputation: 11317
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:
bool
in favor of short
, though it breaks all sense of intention.bool
by bitset, however different values can't have different namesstatic 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?
Upvotes: 5
Views: 682
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
Reputation: 302738
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