模板层次结构中的可选虚函数取决于参数(optional virtual function in template hierarchy depending on parameter)

编程入门 行业动态 更新时间:2024-10-17 15:29:30
模板层次结构中的可选虚函数取决于参数(optional virtual function in template hierarchy depending on parameter)

我有一个模板层次结构,我希望它具有clone()函数,具体取决于模板类型是否是可复制构造的。 作为第一步,我想从附加参数bool Clonable开始:

template<class T, bool Clonable> class Base { T t; void foo(); virtual void bar(); virtual unique_ptr<Base> clone() const = 0; //should be only for Clonable=true }; template<class T, bool Clonable> class Derived : public Base<T, Clonable> { virtual void bar() override; virtual unique_ptr<Base> clone() const override; ////should be only for Clonable=true };

不幸的是,虚函数的实例化并不依赖于它们是否被调用。 所以我想我应该选择部分专业化。 但是,直截了当的方式导致了很多代码重复。 任何人都可以通过最少的代码重复推荐实现这一目标的方法吗?

I have a template hierarchy, and I want it to have clone() function depending on whether template type is copy-constructible. As a first step I want to begin with additional parameter bool Clonable:

template<class T, bool Clonable> class Base { T t; void foo(); virtual void bar(); virtual unique_ptr<Base> clone() const = 0; //should be only for Clonable=true }; template<class T, bool Clonable> class Derived : public Base<T, Clonable> { virtual void bar() override; virtual unique_ptr<Base> clone() const override; ////should be only for Clonable=true };

Unfortunately, instantiation of virtual functions does not depend on whether they are called or not. So I suppose that I should go with partial specialization. However, straightforward way leads to very much of code duplication. Could anyone recommend the way to achieve this with minimum code duplication?

最满意答案

不幸的是,与此处的一些评论相反,SFINAE无法帮助您。 这是因为模板类的非模板成员不被视为模板,因此不能成为SFINAE: http ://coliru.stacked-crooked.com/a/258e20a0293d93f0。 解决此问题的标准方法通常是以简单的方式使其成为模板:

template <class U = T, std::enable_if ... > virtual std::unique_ptr<Base> clone() const = 0;

但虚函数不能是模板,所以这不起作用。

在这种情况下避免重复的方法是从有条件地拥有该成员的类继承:

template <class Base, bool Cloneable> struct CloneInterface; template <class Base> struct CloneInterface<Base, false> {}; template <class Base> struct CloneInterface<Base, true> { virtual unique_ptr<Base> clone() const = 0; }

现在你只是继承:

template<class T, bool Clonable> class Base : CloneInterface<Base<T, Clonable>, Clonable> { T t; void foo(); virtual void bar(); };

请注意,我们从派生时模板化的基类继承(有问题的派生类称为Base ,以使事情更加混乱:-))。 这种技术称为CRTP,它非常强大,因为它可以将接口和实现注入到类中,正如您所看到的那样,也可以有条件地执行此操作。

为了实现,我们再次使用CRTP:

template <class T, bool Clonable, class D> struct BaseHelper; template <class T, class D> struct BaseHelper<T, false, D> : Base<T, false> {}; template <class T, class D> struct BaseHelper<T, true, D> : Base<T, true> { unique_ptr<Base<T, true>> clone() override { return make_unique<D>(static_cast<D&>(*this)); } }; template<class T, bool Clonable> class Derived : public BaseHelper<T, Clonable, Derived<T, Clonable>> { virtual void bar() override; };

Unfortunately, contrary to a few of the comments here, SFINAE cannot help you here. That's because a non-template member of a template class is not considered a template, and therefore cannot be SFINAE'ed out: http://coliru.stacked-crooked.com/a/258e20a0293d93f0. The standard approach to solve this would typically to make it a template in a trivial way:

template <class U = T, std::enable_if ... > virtual std::unique_ptr<Base> clone() const = 0;

But virtual functions can't be templates, so this doesn't work.

The way to avoid repetition in this case is to inherit from a class that conditionally has the member:

template <class Base, bool Cloneable> struct CloneInterface; template <class Base> struct CloneInterface<Base, false> {}; template <class Base> struct CloneInterface<Base, true> { virtual unique_ptr<Base> clone() const = 0; }

And now you just inherit:

template<class T, bool Clonable> class Base : CloneInterface<Base<T, Clonable>, Clonable> { T t; void foo(); virtual void bar(); };

Notice that we inherit from a base class that is templated on the derived (the derived class in question is called Base, to make things more confusing :-) ). This technique is called CRTP and it is quite powerful as it can inject interface and implementations into classes, and as you can see can do so conditionally as well.

To get the implementation, we use CRTP again:

template <class T, bool Clonable, class D> struct BaseHelper; template <class T, class D> struct BaseHelper<T, false, D> : Base<T, false> {}; template <class T, class D> struct BaseHelper<T, true, D> : Base<T, true> { unique_ptr<Base<T, true>> clone() override { return make_unique<D>(static_cast<D&>(*this)); } }; template<class T, bool Clonable> class Derived : public BaseHelper<T, Clonable, Derived<T, Clonable>> { virtual void bar() override; };

更多推荐

本文发布于:2023-04-28 05:15:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1330338.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:可选   函数   层次   模板   参数

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!