You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类引用成员名无法作为非类型模板参数,有何替代方案?

问题描述

我有一个工具生成的类,成员变量名称不固定,希望通过单个模板类访问这些成员。原本使用非类型成员指针可以实现该需求(示例代码如下):

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:27:33