如果类继承自 2 个模板化父类,则调用不明确。为什么?

Pat*_*ick 5 c++ templates multiple-inheritance visual-c++-2010

我有一个模板化类,它对作为模板参数给出的类执行操作。对于我的某些课程,我想将功能“分组”在一个课程中,以便调用者更轻松。事实上,代码看起来像这样(名称已更改):

template<typename T>
class DoSomeProcessing
{
public:
   process(T &t);
};

class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};
Run Code Online (Sandbox Code Playgroud)

问题是,当我使用 CustomerOrder 作为参数调用 ProcessingFrontEnd::process 时,编译器会抱怨它。

我尝试在较小的测试应用程序中重现该问题。这是代码:

#include <vector>

class X : public std::vector<char>
        , public std::vector<void *>
{
};

int main(void)
{
X x;
x.push_back('c');
return 0;
}
Run Code Online (Sandbox Code Playgroud)

事实上,如果编译,微软的 VS2010 编译器会给出这个错误:

test.cpp
test.cpp(11) : error C2385: ambiguous access of 'push_back'
        could be the 'push_back' in base 'std::vector<char,std::allocator<char> >'
        or could be the 'push_back' in base 'std::vector<void *,std::allocator<void *> >'
test.cpp(11) : error C3861: 'push_back': identifier not found
Run Code Online (Sandbox Code Playgroud)

我用不同的类型(char+void*、double+void*)和调用中的不同参数('c',3.14)测试了这个测试应用程序,但是错误信息总是一样的。

我用 VS2005 和 VS2010 对此进行了测试,但我总是遇到相同的错误。

为什么编译器不能确定要调用的正确函数?是什么让编译器感到困惑?或者它只是微软编译器中的一个错误?

编辑: 如果我明确地向我的班级添加 2 个 push_back 方法,如下所示:

class X : public std::vector<char>
        , public std::vector<void *>
{
public:
   void push_back(char c) {}
   void push_back(void *p) {}
};
Run Code Online (Sandbox Code Playgroud)

编译器不再抱怨。因此,通过这些方法,他可以清楚地区分字符和空指针。如果这两个 push_back 方法是从父级继承的,他为什么不能这样做?

Dav*_*vid 4

这是设计使然。编译器不会尝试解析重载函数,因为它们不是重载函数。标准对此非常明确(见 10.2.2)。如果在两个不同的碱基中找到相同的名称,则这是一个歧义,即使它们可以通过调用正确解析(即在您的情况下)。不同类中的同名函数通常具有完全不同的目的,因此不应根据其参数进行选择。有很多充分的理由不允许这样做,但这是一个。

想象一下您的类 C 派生自 A 和 B,并且这两个基类来自两个不同的库。如果 B 的作者向类添加新函数,则可能会通过将调用从 A::foo() 重定向到 B::foo()(如果后者更匹配)来破坏用户的代码。

如果您希望以与单个类的一部分相同的方式处理这两个函数,那么最好的方法是在派生类中使用声明。只需添加

using std::vector<char>::push_back;
using std::vector<void *>::push_back;
Run Code Online (Sandbox Code Playgroud)

到 X 类的声明。