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