测试Fold expression与CRTP遇Play方法调用歧义编译错误求助
问题分析
你的代码里MyMap<A, B>同时继承了BaseValue<A>和BaseValue<B>,这两个基类都定义了名为Play的成员函数。虽然它们的参数类型分别是const A&和const B&,但C++的名字查找规则是先找名字,再做重载解析。当你调用oMyMap.Play(a)时,编译器会在MyMap的所有基类中查找名为Play的函数,结果找到了两个同名函数,此时重载解析还没开始就因为名字冲突产生了歧义。
解决方案
这里提供几种可行的解决方法:
方法1:在派生类中引入所有基类的Play函数
通过using声明结合C++17折叠表达式,把所有基类的Play成员引入到MyMap的作用域中,这样编译器就能对这些函数进行正常的重载解析:
template<typename... Keys> struct MyMap : public BaseValue<Keys>... { using BaseValue<Keys>::Play...; // 引入所有基类的Play函数 };
修改后,调用oMyMap.Play(a)时,编译器会根据参数类型自动匹配到BaseValue<A>::Play(const A&),歧义消除。
方法2:显式指定基类调用
如果不想修改MyMap的定义,可以在调用时显式指定要调用的基类版本:
oMyMap.BaseValue<A>::Play(a);
这种方式虽然能解决问题,但代码可读性差,不推荐在频繁调用的场景使用。
方法3:改用模板成员函数替代多重继承
直接重构结构,去掉BaseValue模板类,在MyMap中定义一个模板版的Play函数,从根源上避免多重继承的名字冲突:
template<typename... Keys> struct MyMap { template<typename TKey> void Play(const TKey& arg) { arg.play(); } };
这种方式更简洁,同样能实现你想要的功能。
验证代码(方法1示例)
修改后的完整代码如下:
#include <iostream> #include <any> using namespace std; struct A { void play() const { std::cout << "A..." << std::endl; } }; struct B { void play() const { std::cout << "B..." << std::endl; } }; template<typename TKey> struct BaseValue { void Play(const TKey& arg) { arg.play(); } }; template<typename... Keys> struct MyMap : public BaseValue<Keys>... { using BaseValue<Keys>::Play...; // 引入所有基类的Play函数 }; int main() { MyMap<A, B> oMyMap; A a; oMyMap.Play(a); B b; oMyMap.Play(b); return 0; }
编译运行后会输出:
A... B...
内容的提问来源于stack exchange,提问作者jsubi
相关产品推荐
相关产品推荐

