Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
449 views
in Technique[技术] by (71.8m points)

metaprogramming - Is there a way to specify and use a list of all data members belonging to a C++ class

When developing C++ code, I often find myself trying to do something for all the data members belonging to a class. Classic examples are in the copy constructor and assignment operator. Another place is when implementing serialization functions. In all of these situations, I have spent a lot of time tracking down bugs in large codebases where someone has added a data member to a class but has not added its usage to one of these functions where it is needed.

With C++11, 14, 17, and 20, there are many template programming techniques that are quite sophisiticated in what they can do. Unfortunately, I understand only a little of template metaprogramming. I am hoping that someone can point me to a way to specify a list of variables (as a class member and/or type) that I can use to help reduce errors where someone has inadvertently left a member out. I am okay with both a compile-time and run-time penalty, as long as there is an easy way at build time to specify whether or not to use such instrumentation.

A notional usage might look like:

class Widget {
    template <typename Archive> void serialize(Archive ar) {
        auto myvl = vl(); // make a new list from the one defined in the constructor
        ar(a);
        ar(x);
        myvl.pop(a);
        myvl.pop(x);

        // a run-time check that would be violated because s is still in myvl.
        if (!myvl.empty())
            throw std::string{"ill-definied serialize method; an expected variable was not used"};
        // even better would be a compile-time check
    }

private:
    int a;
    double x;
    std::string s;
    VariableList vl(a, x, s);
};

Or perhaps some static analysis, or ...

I am just looking for a way to improve the quality of my code. Thanks for any help.

question from:https://stackoverflow.com/questions/66056639/is-there-a-way-to-specify-and-use-a-list-of-all-data-members-belonging-to-a-c

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This feature is coming with the (compile time) reflection feature. https://root.cern/blog/the-status-of-reflection/ talks about its status at a technical level last year.

Reflection is a c++23 priority, and is likely to be there.

Before that, one approach I do is write a single point of failure for all such operations. I call it as_tie:

struct Foo {
  int x,y;
  template<class Self, std::enable_if_t<std::is_same_v<Foo, std::decay_t<Self>>, bool> =true>
  friend auto as_tie(Self&& self){
    static_assert(sizeof(self)==8);
    return std::forward_as_tuple( decltype(self)(self).x, decltype(self)(self).y );
  }
  friend bool operator==(Foo const&lhs, Foo const& rhs){
    return as_tie(lhs)==as_tie(rhs);
  }
};

or somesuch depending on dialect.

Then your seializer/deserializer/etc can use as_tie, maybe using foreach_tuple_element. Versioning can even be done; as_tie_v2_2_0 for an obsolete tie.

And if someone adds a member, the sizeof static assert probably fires.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...