I have a class which is generated from a tool with member variable names that vary. I would like to use a single templated class to access these members. I can do this in the following way by using a non-type member pointer:
template<typename MODULE,
int MODULE::*a> class Foo {
public:
Foo() {
MODULE mod;
std::cout << mod.*a;
}
};
struct Bar {
int random_name01234{20};
};
int main(int argc, char** argv, char** env) {
Foo<Bar, &Bar::random_name01234> foobar;
}
However, the generated class (Bar in this example) uses references to members I do not have access to. I cannot pass a reference as a non-type template parameter as described here - Reference as a non-type template argument:
template<typename MODULE,
int& MODULE::*a> class Foo {
public:
Foo() {
MODULE mod;
std::cout << mod.*a;
}
};
class Bar {
private:
int random_name01234{20};
public:
int& random_name01234_ref{random_name01234};
};
int main(int argc, char** argv, char** env) {
Foo<Bar, &Bar::random_name01234_ref> foobar;
}
error: cannot create pointer to reference member ‘Bar::random_name01234_ref’
Is there another way I can approach this to pass the random member names to a templated function?
CodePudding user response:
You cannot have a pointer to reference member (see eg How to obtain pointer to reference member? and Reference as a non-type template argument), but you can have a pointer to member function that returns the value by reference:
#include <iostream>
template<typename MODULE,
int& (MODULE::*a)()> class Foo {
public:
Foo() {
MODULE mod;
std::cout << (mod.*a)();
}
};
class Bar {
private:
int random_name01234{20};
public:
int& random_name01234_ref{random_name01234};
int& get() { return random_name01234_ref;}
};
int main(int argc, char** argv, char** env) {
Foo<Bar, &Bar::get> foobar;
}
If you cannot modify Bar
then you just have to use a different callable that returns the reference. Anyhow I consider int (MODULE::*a)()
as too non-generic. I'd rather let Foo
accepts any callable, for example a lambda expression:
#include <iostream>
template<typename MODULE, typename F> class Foo {
public:
Foo() {
MODULE mod;
std::cout << F{}(mod);
}
};
class Bar {
private:
int random_name01234{20};
public:
int& random_name01234_ref{random_name01234};
};
int main(int argc, char** argv, char** env) {
Foo<Bar,decltype([](Bar& b)->int&{ return b.random_name01234_ref;})> foobar;
}
Lambda expression in unevaluated context is only available since C 20. Before it works as well, just a little more verbose.