C++模板中调用重载operator()无法修改类成员变量值
C++模板传值导致对象修改未生效的原因与解决方法
问题的核心原因是模板函数的参数采用了传值传递:
当你调用NodeWalk(obj)时,模板参数T action会创建一个Foo对象的副本。你在重载的operator()里修改的是这个副本的bar_成员,而非原对象obj的bar_。函数执行完毕后,副本被销毁,原对象的状态完全没有被改变,所以后续调用obj.GetBar()得到的还是初始值1。
具体流程拆解
main中创建Foo obj,其bar_初始化为1;- 调用
NodeWalk(obj)时,参数action是obj的拷贝,此时存在两个独立的Foo对象:原对象obj和副本action; - 在
NodeWalk内调用action(),修改的是副本action的bar_,所以内部打印显示bar_ = 2; NodeWalk执行结束,副本action被销毁,回到main后访问原对象obj的bar_,值仍为初始的1。
解决方法
将模板函数的参数改为引用传递,这样就会直接操作原对象,而非创建副本。修改后的模板函数如下:
template <typename T> int NodeWalk(T& action) { // 将参数改为引用类型 action(); return 0; }
修改后再运行代码,输出会变为:
print in the operator: bar_ = 2 print outside the operator: bar_ = 2
如果需要支持传入临时对象(比如NodeWalk(Foo())),可以使用万能引用配合std::forward实现完美转发,写法如下:
#include <utility> // 需要包含头文件 template <typename T> int NodeWalk(T&& action) { std::forward<T>(action)(); return 0; }
这种写法既支持左值(如原代码中的obj),也支持右值(临时对象),但对于你的当前场景,第一种普通引用的修改方式已经足够解决问题。
内容的提问来源于stack exchange,提问作者ada liu
相关产品推荐
相关产品推荐

