用多态函数覆盖模板化函数
如果我有
template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override
一个类
class A : public TalkySerialisable {
...}
然后如果我执行
TalkyBuffer b;
A test;
b << test;
那么gcc将调用模板函数而不是覆盖函数
但是如果我专门定义了一个覆盖
TalkyBuffer& operator<<(A const &object); // Override without polymorphism
那么gcc会选择那个。 有没有一种实用的方法可以用抽象类覆盖模板化函数?
我读过这篇文章,但它并没有阐明当你将多态性融入其中时会发生什么: http://www.gotw.ca/publications/mill17.htm 另外,我在这里找不到解决方案,但也许我使用了错误的术语。
If I have
template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override
and a class
class A : public TalkySerialisable {
...}
Then if I perform
TalkyBuffer b;
A test;
b << test;
Then gcc is calling the Template function rather than the Override function
However if I specifically define an override
TalkyBuffer& operator<<(A const &object); // Override without polymorphism
Then gcc picks that one.
Is there a practical way to override a templated function with an abstract class?
I read this but it doesn't shed light onto what happens when you throw polymorphism into the mix:
http://www.gotw.ca/publications/mill17.htm
Also I couldn't find a solution here but perhaps I'm using the wrong terms.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
定义函数
TalkyBuffer&时运算符<<(TalkySerialisable const &object);
您没有覆盖。您正在重载 tmeplate 函数。但是,当编译器看到
b << test;
,它搜索需要A
的运算符。它有一个,它是不需要自动转换的模板化函数。这是最好的选择。重载函数需要对参数进行自动转换(从 A 到 TalkySerialisable)以适合声明,这不是最佳选择。
When defining the function
TalkyBuffer& operator<<(TalkySerialisable const &object);
You are not overriding. You are overloading the tmeplated function.But, when the complier sees
b << test;
, it searches for an operator that wants anA
. It has one, it's the templated function that requires no automatic cast. This is the best choice.The overloaded function requires an automatic cast (from A to TalkySerialisable) on the parameters to fit the declaration, and is not the best choice.
我认为可以使用一个简单的基于函数的解决方案,重用函数重载进行推导。
现在,让我们实现您的自定义类:
并创建一个派生类:
那么,会发生什么?
serialize
的重载时,将拾取TalkyBuffer::operator<<(T const&)
dispatch 的结果
dispatch
的结果时,dispatch(TalkySerialized const&)
比dispath(...)
,因此返回类型是specialized
serialize
(没有从specialized 进行转换)
到generic
),因此继承开始发挥作用I think it's possible to use a simple
function
based solution, reusing function overload for derivation.Now, let's implement your custom class:
And create a derived one:
So, what happens ?
TalkyBuffer::operator<<(T const&)
will be picked upserialize
, it will first compute the result ofdispatch
dispatch
,dispatch(TalkySerializable const&)
is a better match thandispath(...)
, thus the return type isspecialized
serialize
cannot be used (there is no conversion fromspecialized
togeneric
), so inheritance kicks in使用
Boost.enable_if
:我不确定这是最好的解决方案,但我未能找到更好的解决方案:专门化模板也不起作用。
正如 @Matthieu 在评论中指出的那样,之前的解决方案有一个主要缺点,即基本模板需要知道它将被重载,这是一种不必要的耦合,会阻碍可扩展性。
为了解决这个问题,我想出了一种使用标签调度的新方法,使用 Boost.MPL 宏。
要为给定类型
T
提供插入运算符的新实现,需要提供一种新类型来充当标记(在我们的示例中为TypeSerialized::tag
),提供了一种将T
与新标签关联的方法(通过使用示例中的嵌套 typedef,或者通过专门化特征类:template <> talky_buffer_trait{ typedef new_tag type };
),最后重载实现函数(示例中的insertionOperatorImpl
)。A solution using
Boost.enable_if
:I'm not sure this is the best solution, but I failed to find a better one: specializing the template does not work either.
As @Matthieu noted in the comment, the previous solution has the major drawback that the base template needs to know that it will be overloaded, which is an unnecessary coupling that hinders extensibility.
To solve this problem, I came up with a new approach using tag dispatching, along with trait classes and compile-time introspection using Boost.MPL macros.
To provide new implementations of the insertion operator for a given type
T
, one needs to provide a new type to act as a tag (TypeSerializable::tag
in our example), provides a way to associateT
with the new tag (either by using a nested typedef as in the example, or by specializing the trait class:template <> talky_buffer_trait<T> { typedef new_tag type };
), and finally overload the implementation function (insertionOperatorImpl
in the example).