Home > Software design >  Create macro to generate getters for any class c
Create macro to generate getters for any class c

Time:01-25

Recently I started thinking how to generalize access to private data members through a generalized class/function by name. The reason is that I have a lot of private members and creating a getter for each one is bothersome. I tried to use preprocessor macros to do the following

#define RETURNS(...) -> decltype((__VA_ARGS__))  { return (__VA_ARGS__); }
#define GET(classname, name, funcname) auto funcname() RETURNS(classname->name);

class foo {
private: 
    int a = 1;
    std::vector<int> b = std::vector<int>(3, 1);
    std::string c = "pika-chuuu";
public:
    foo() = default;
    ~foo() = default;

    GET(this, a, getter);
};

int main(const int argc, char* argv[]) {

    foo obj;
    std::cout << obj.getter();
    return 0;
}

This one compiles, but is there a way I can create a getter in foo, which takes the name of a variable at run-time and returns this->(name)? Using this approach I can reduce the code for introducing getters, nevertheless the more data members there are, the more getters I need, but I would like to have one to get access to any data member by name. Do you have any suggestion of how can it be done? I'm looking for a syntax like this:

#define RETURNS(...) -> decltype((__VA_ARGS__))  { return (__VA_ARGS__); }
#define GET(classname, name) RETURNS(classname->name);
class foo {
private: 
    int a = 1;
    std::vector<int> b = std::vector<int>(3, 1);
    std::string c = "pika-chuuu";
public:
    foo() = default;
    ~foo() = default;

    auto getter(auto x) GET(this, x);
};

Here x is the name I put as input, either a,b or c

CodePudding user response:

Do you have any suggestion of how can it be done?

Why all the decltype and -> and variadic macro with __VA_ARGS__ and RETURNS and ... Just:

#include <vector>
#include <string>

#define DECL_GETTER(name) \
        auto get_##name() { return this->name; }

class foo {
private: 
    int a = 1;
    std::vector<int> b = std::vector<int>(3, 1);
    std::string c = "pika-chuuu";
public:
    DECL_GETTER(a)
    DECL_GETTER(b)
    DECL_GETTER(c)
};

int main() {
    foo f;
    f.get_a();
    f.get_b();
    f.get_c();
}

I would also add const overload when by it.

You may want to research QT properties system, that is basically like a more advanced version of this.

Subjective: TBH with such one macro you are making abstractions where they are not needed. Is it worth the time? It hides some obvious code with non-obvious macro, makes IDE "jump to definition" harder, makes maintenance and reasoning harder. Renaming variables with IDE features will be harder. Consider just writing those getters by hand verbatim - consider readable and clear code that is obvious on the first look, even when you have to sacrifice a little repetition and type () { return some more characters. Configure your IDE, so you can have "create a getter/setter for this member function" action to speed up your development (see for example QT Creator, it's one feature that is really nice there).

is there a way I can create a getter in foo, which takes the name of a variable at run-time and returns this->(name)?

C is a language without reflection, so basically no, or it would require way more boilerplate code than it is worth.

CodePudding user response:

Revision:

As @HolyBlackCat mentioned, there is no need to heap allocation, and you should use the impl class as object directly:

class foo{
    struct foo_data
    {
        int i;
        std::string s;
    };
    foo_data data;
public:
    template<typename ... Args>
    foo(Args&& ... args)
    : data(std::forward<Args>(args)...)
    {}

    foo_data const* operator->() const   // Returns a pointer to const data
    {
        return &data;
    }
};

Then to access the data:

int main()
{
    auto f = foo(3, "hello");
    std::cout << f->i << f->s;          // Accessing data, prints: "3hello"
    // f->i  = 1;                       // Error: assignment of member in read-only object
}
  •  Tags:  
  • Related