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

测试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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:18:24