类引用成员名无法作为非类型模板参数,有何替代方案?
问题描述
我有一个工具生成的类,成员变量名称不固定,希望通过单个模板类访问这些成员。原本使用非类型成员指针可以实现该需求(示例代码如下):
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; }
但该生成类中,我无法直接访问目标成员,只能访问其公开的引用。尝试将引用作为非类型模板参数传递时触发编译错误(示例代码及错误信息如下):
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’
请问是否有其他方法可将这类随机命名的成员传递给模板类?
解决方案
C++标准不允许定义指向引用类型成员的指针,这是触发编译错误的核心原因。以下是几种可行的替代方案:
1. 用成员函数指针封装访问逻辑
将获取成员引用的操作包装成一个成员函数,再将该函数的指针作为非类型模板参数传递:
template<typename MODULE, int& (MODULE::*getter)()> class Foo { public: Foo() { MODULE mod; std::cout << (mod.*getter)(); } }; class Bar { private: int random_name01234{20}; public: int& get_random_member() { return random_name01234_ref; } int& random_name01234_ref{random_name01234}; }; int main() { Foo<Bar, &Bar::get_random_member> foobar; }
如果无法修改工具生成的类,也可以编写外部辅助函数模板,在函数内直接访问公开的成员引用:
template<typename MODULE> int& get_member_ref(MODULE& mod) { return mod.random_name01234_ref; } template<typename MODULE, int& (*getter)(MODULE&)> class Foo { public: Foo() { MODULE mod; std::cout << getter(mod); } }; int main() { Foo<Bar, get_member_ref<Bar>> foobar; }
2. 利用C++20的无捕获lambda作为模板参数
C++20允许将无捕获lambda作为非类型模板参数,直接在模板实例化时定义成员引用的访问逻辑,无需额外编写函数:
template<typename MODULE, auto Getter> class Foo { public: Foo() { MODULE mod; std::cout << Getter(mod); } }; class Bar { private: int random_name01234{20}; public: int& random_name01234_ref{random_name01234}; }; int main() { Foo<Bar, [](Bar& mod) -> int& { return mod.random_name01234_ref; }> foobar; }
这种方式灵活性极高,无需修改原有类,直接在模板使用时指定访问规则。
3. 运行时绑定访问器(类型擦除)
如果对编译期性能要求不高,或者需要动态切换访问目标,可以用std::function封装访问逻辑,在运行时传入模板类:
#include <functional> template<typename MODULE> class Foo { public: using MemberGetter = std::function<int&(MODULE&)>; Foo(MemberGetter getter) { MODULE mod; std::cout << getter(mod); } }; int main() { Foo<Bar> foobar([](Bar& mod) -> int& { return mod.random_name01234_ref; }); }
这种方式放弃了编译期绑定的特性,但能满足随机命名成员的访问需求,且代码更简洁。
内容的提问来源于stack exchange,提问作者ttchuk
相关产品推荐
相关产品推荐

