调用派生类的模板函数
我在 C++ 中遇到问题,在拥有指向基类的指针的同时调用派生类的函数。
编辑: 一些答案让我参考 CRTP
但我的观点是我需要一个指向“ Base*”类而不是“Base*”,因为我不知道当前正在处理的类型(当前实例是从某种工厂创建的)。
类:
class Base
{
..
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
用法:
int main()
{
Base* BasePtr = new Derived1();
// The expected function to be called is Derived1::func<int>()
BasePtr->func<int>();
return 0; // :)
}
我无法将 func 设为虚拟,因为该语言不支持虚拟模板函数。
仅当只有类具有模板参数时才允许,但如果类中的函数具有模板参数则不允许。
我在 Boost.Serialization 中看到类似的问题得到解决,但无法理解解决方案。
谢谢,
科比·梅尔
I'm having a problem in C++ with calling a function of a derived class while having a pointer to the base class.
EDIT:
Some answers referred me to CRTP
but my point is that I need to have a pointer to the "Base*" class not "Base*" because I'm unaware of the type currently being handled (The current instance is created from some sort of a factory).
Classes:
class Base
{
..
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
class Derived1 : public Base
{
...
template<typename T>
func (T arg) { ... };
};
Usage:
int main()
{
Base* BasePtr = new Derived1();
// The expected function to be called is Derived1::func<int>()
BasePtr->func<int>();
return 0; // :)
}
I can't make func virtual because the language does not support virtual template function.
It is only allowed if only the class is have template arguments but not if the function within it has template arguments.
I have seen a similar problem resolved within Boost.Serialization but couldn't understand the solution.
Thanks,
Koby Meir
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实施奇怪的重复模板模式 (CTRP)。
插图:
Implement Curiously recurring template pattern(CTRP).
Illustration:
现有的两种解决方案将动态多态性换成了静态多态性。如果没有关于当前问题的更多详细信息,就不可能知道这是否是一种有效的方法,因为它基本上打破了多态层次结构:对于 CRTP 来说,没有单一的基类,而是一个基类。您不能将
Derived1
和Derived2
的对象放在同一个容器中,因为它们不相关...如果您只需要共享代码,但不共享代码,那么这是一个很好的解决方案如果你需要动态多态性。查看访客模式和双重调度以解决类似问题。如果您需要动态多态性,您可以尝试实现双重分派(这很痛苦,但如果层次结构足够小,则可行。基本上创建两个不同的层次结构,一个以
Base
为根,另一个作为缺少手动调度程序。以Base
为根的层次结构将具有一个虚拟方法apply
,第二个层次结构将为第一个层次结构中的每个类型提供虚拟函数。 :我使用的名称在Visitor模式中很常见,这种方法与该模式非常相似(我不敢称其为Visitor模式,但方法类似,所以我只是借用了
User的 命名约定)。代码将类似于:
通过将函数的参数从引用更改为 const 引用(如果可能),可以释放事先声明::visit( Derived1& ),此时两个对象都已解析为其静态类型。当
i
和c
的要求。真正的魔力在于,在 [1] 中,C++ 单一调度机制仍将调用调度到Derived1::apply
,因为这是BasePtr
指向的对象的动态类型。此时它将以自身作为参数调用Visitor::visit( Derived1& )
。它将再次通过单一调度机制调度到 FooCallerFooCaller::visit
调用call_foo
时,参数U
被推导为Derived1
,当它调用时Derived1::foo
参数被推断为int
并且最终调用Derived1::foo
...尽管有几个循环和间接...根据您的特定用例,这可能太复杂(如果像 CRTP 这样的静态多态性可以工作)或太难维护(如果层次结构很大:对于
Base< 中的每个新元素/code> 层次结构,您必须更新
Visitor
层次结构中的所有类型),因此,如果您可以避免这种复杂性,那就完美了。但在某些情况下,您需要这个。另请注意,这是最复杂的完全动态解决方案,两者之间还有其他选项,具体取决于您需要运行时多态性......可能是这样的情况,您的层次结构模型是短裤的访问者,并且您只需要手动展开将在内部分派到模板的不同虚拟函数,在这种情况下,上述复杂性将消失一半。
另请注意,这在 C++ 中很不寻常,如果您解释手头的实际问题,可能会有更好的更简单的解决方案,您所说的是原始问题的解决方案的要求:动态分派到模板。
The two existing solutions trade dynamic polymorphism for static polymorphism. Without more details on the problem at hand, it is not possible to know whether that is a valid approach or not, as it basically breaks the polymorphic hierarchy: with CRTP there is no single base class, but rather a family of them. You cannot hold objects of
Derived1
andDerived2
in the same container as they are unrelated... It is a fine solution if all you need is to share the code, but not if you need dynamic polymorphism. Take a look at the Visitor pattern and at double-dispatch for similar problems.If you need dynamic polymorphism, you could try to implement double dispatch (it is a pain, but feasible if the hierarchy is small enough. Basically create two different hierarchies, one rooted at
Base
and another that serves as some short of manual dispatcher. The hierarchy rooted atBase
will have a virtual methodapply
, and the second hierarchy will have virtual functions for each one of the types in the first hierarchy:The names I have used are common in the Visitor pattern, and this approach is quite similar to that pattern (I don't dare call it the Visitor pattern, but the approach is similar, so I just borrowed the naming convention).
User code would be similar to:
The requirement of declaring
i
andc
before hand can be released by changing (if possible) the arguments to the functions from references to const-references. The actual magic is that in [1] the C++ single dispatch mechanism sill dispatch the call toDerived1::apply
, since that is the dynamic type of the object pointed byBasePtr
. At that point it will callVisitor::visit( Derived1& )
with itself as the argument. That will again be dispatched through the single dispatch mechanism toFooCaller<int>::visit( Derived1& )
, and at that point both objects have been resolved to their static types. WhenFooCaller<int>::visit
callscall_foo
the argumentU
is deduced to beDerived1
, when it callsDerived1::foo
the argument is deduced to beint
and it ends up callingDerived1::foo<int>
... though a couple of loops and indirections...Depending on your particular use case this might be too complex (if static polymorphism like CRTP would work) or too hard to maintain (if the hierarchy is big: for each new element in the
Base
hierarchy you will have to update all types in the hierarchy of theVisitor
), so if you can avoid this complexity, perfect. In some cases, though, you need this.Also note that this is the most complex fully dynamic solution, there are other options in between, depending on what is it that you need to be runtime polymorphism... It might be the case that your hierarchy models a visitor of shorts, and that you only need to manually unroll the different virtual functions that will dispatch to the template internally, in which case half of the above complexity will be gone.
Also note that this is quite unusual in C++, and that if you explain the actual problem at hand, there might be better simpler solutions, what you have stated are the requirements of your solution to the original problem: dynamically dispatch to a template.
检查这个,它将帮助您实现 CRTP。
Check this out, it will help you implement the CRTP.