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

发布于 2024-09-15 22:12:12 字数 1524 浏览 3 评论 0原文

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

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

class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};

问题是,当我使用 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;
}

事实上,如果编译了此代码,Microsoft 的 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

我使用不同类型(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) {}
};

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

I have a templated class that performs an action on the class that is given as template argument. For some of my classes I want to 'group' the functionality in one class, to make it easier for the caller. In fact the code looks something like this (names were changed):

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

class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};

The problem is that when I call ProcessingFrontEnd::process with a CustomerOrder as argument, that the compiler complains about it.

I tried to reproduce the problem in a smaller test application. This is the code:

#include <vector>

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

int main(void)
{
X x;
x.push_back('c');
return 0;
}

And indeed, if this is compiled, Microsoft's VS2010 compiler gives this error:

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

I tested this test application with different types (char+void*, double+void*) and different arguments in the call ('c', 3.14), but the error message is always the same.

I tested this with VS2005 and VS2010 but I always get the same error.

Why can't the compiler determine the correct function to call? What makes this confusing for the compiler? Or is it just a bug in the Microsoft compiler?

EDIT:
If I explicitly add 2 push_back methods to my class, like this:

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

The compiler doesn't complain anymore. So with these methods he can clearly distinguish between a character and a void-pointer. Why can't he do this if the two push_back methods are inherited from the parent?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一曲琵琶半遮面シ 2024-09-22 22:12:12

这是设计使然。编译器不会尝试解析重载
函数,因为它们没有重载
功能。标准对此非常明确
(见 10.2.2)。如果发现两个名字相同
不同的基础,这是一个歧义,即使它们
可以通过调用正确解决(即在
你的情况)。不同类中的同名函数通常具有完全不同的目的,因此不应基于以下因素进行选择:
他们的论点。有很多充分的理由不这样做
允许这样,但这里有一个。

想象一下你的 C 类派生自 A 和 B 并且
这两个基类来自两个不同的
图书馆。如果B的作者添加了一个新功能
对于班级来说,它可能会破坏用户的代码
将调用从 A::foo() 重定向到 B::foo() 如果
后者是更好的匹配。

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

using std::vector<char>::push_back;
using std::vector<void *>::push_back;

到 X 类的声明中即可。

This is by design. The compiler is not trying to resolve overloaded
functions because these are not overloaded
functions. The standard is really clear on that
(see 10.2.2). If the same name is found in two
different bases, it's an ambiguity, even if they
could be resolved correctly with the call (i.e. in
your case). Same-named functions in different classes will typically have quite different purposes and hence the selection between them should not be made on the basis of
their arguments. There are many good reasons not to
allow that, but here's one.

Imagine your class C derives from A and B and
these two base classes come from two different
libraries. If the author of B adds a new function
to the class, it may break the user's code by
redirecting a call from A::foo() to B::foo() if
the latter is a better match.

If you want the two functions to be treated in the same way that they would
be if part of a single class, then the best way to do it is with using
declarations in the derived class. Just add

using std::vector<char>::push_back;
using std::vector<void *>::push_back;

to the declaration of class X.

宛菡 2024-09-22 22:12:12

我相信您违反了 C++ 重载规则,该规则禁止跨类重载< /a>.如果您的模板类是两个单独的类,每个类都有自己的 process(CustomerOrder)process(ProductionOrder) 成员,您将获得相同的结果。

解决方法是在派生类中显式使用 using 语句,从每个模板基类中引入每个重载。

I believe you are running afoul of the C++ overloading rules which prohibit overloading across classes. You'd get the same results if your template classes were two separate classes, each with its own process(CustomerOrder) and process(ProductionOrder) member.

The workaround is explicit using statements inside your derived class, pulling in each overload from each of the template base classes.

流年已逝 2024-09-22 22:12:12

编译器如何知道您要调用哪个进程?有两个选择。您想要两个、一个还是另一个?

您需要重写派生类中的过程。

How is the compiler supposed to know which process you want to call? There's two options. Do you want both, one, or the other?

You need to override process in the derived class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文