C++模板类成员函数声明const后重载决议失败问题求解
问题原因解释
你遇到的输出不符合预期是C++重载决议规则的正常结果:
- 执行
b.foo(a)时,b是非const的B<int>实例 - 第一个重载
void foo(B<T> &x)const是const成员函数,非const对象调用它时需要对this指针做const限定隐式转换 - 第二个模板重载
template<class F> void foo(F f)可以直接推导出F = B<int>&,属于完全匹配,不需要任何隐式转换 - 重载决议时完全匹配的优先级高于需要隐式转换的版本,因此编译器优先选择了模板重载,导致两次调用都输出
foo_F
解决方案
无需修改两个重载的const修饰符,只需要通过SFINAE限制模板重载的适用场景,当传入参数是B<T>类型时禁用模板重载即可:
- 首先添加类型特性头文件引用:
#include <type_traits>
- 修改模板版本的
foo声明:
template<class T> class B{ public: void foo(B<T> &x)const; // 仅当F不是B<T>类型时启用该模板重载 template<class F, typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, B<T>>>> void foo(F f); };
- 其余的函数实现和
main逻辑无需修改,运行后即可得到预期输出:
foo_B foo_F
备选方案
如果不希望修改类的定义,也可以在调用foo处理同类型实例时,显式将对象转为const引用:
std::as_const(b).foo(a);
该方法需要修改所有调用同类型参数foo的位置,适合临时调整场景。
内容的提问来源于stack exchange,提问作者user1407220
相关产品推荐
相关产品推荐

