基类中使用 this 指针的模板函数
Posted
技术标签:
【中文标题】基类中使用 this 指针的模板函数【英文标题】:Template function in base class using this-pointer 【发布时间】:2014-04-21 21:12:39 【问题描述】:考虑以下代码:
struct Base
~Base()
virtual double operator()(double x) const = 0;
;
template<typename F, typename G> struct Compose; //forward declaration of Compose
struct Derived1 : public Base //plus many more derived classes
virtual double operator()(double x) const return x;
template <typename F>
Compose<Derived1,F> operator()(const F& f) const return Compose<Derived1,F>(*this,f);
;
template<typename F, typename G>
struct Compose : public Base
Compose(const F &_f, const G &_g) : f(_f), g(_g)
F f;
G g;
virtual double operator()(double x) const return f(g(x));
;
void test()
Derived1 f,g;
auto h=f(g);
这里的 compose 类接受两个派生类 f,g 并通过 operator() 返回组合 f(g(x))。
是否有可能避免在许多派生类中的每一个中显式定义,并在基类中添加一个函数?
编辑:为了更好地解释我在寻找什么:原则上,我想在基类中添加如下内容
template<typename F> Compose<decltype(*this), F>
operator()(const F& f) return Compose<decltype(*this), F>(*this,f);
我尝试了这个,希望 decltype(*this) 自动插入派生类的类型。但它似乎不像这样工作......
解决方案:我终于找到了办法,那就是通过CRTP。然后 Base 类采用以下形式
template<typename Derived>
struct Base
~Base()
virtual double operator()(double x) const = 0;
template<typename F> Compose<Derived, F>
operator()(const F& f) return Compose<Derived, F>(static_cast<Derived const&>(*this),f);
;
派生类是从
struct Derived1 : public Base<Derived1>
【问题讨论】:
如果我们从 编译 的代码开始,但并没有达到您想要的效果,那将会很有帮助。第一个来源在这方面失败了(出于多种原因),第二个来源也是如此,因此很难进入这个问题,更不用说小马可行的替代方案了。 (并且Compose
不是一个函数;它看起来像一个模板类,但目前甚至不是那个)。
你是对的。我会在几分钟内更新它(这里和那里几个逗号;-))。
完成。在 MSVC 11 中编译。
不作为答案包含在内,因为它与您似乎正在寻找的虚拟模型剥离,但您也可以考虑使用 CRTP 作为选项的静态多态性 (See it live)。这可能会让你大吃一惊。
【参考方案1】:
鉴于您的Base
是纯虚拟的,因此可以将模板功能移至Base
。无论如何,所有派生类都必须实现double operator()(double x)
并委托。
我还使用了Base
指针而不是实例,因为正如您指出的那样,否则它在Compose
结构中不起作用(可能想要更改那里的实现以使其不易泄漏......)。
请注意,我从您的层次结构中取出了Compose
(看起来它可以用于更通用的目的) - 随时将它放回原处(它将允许无休止的组合)。
我还删除了所有 const
,因为 struct
需要为 const 对象提供默认 CTOR(随意放入它们)。
我重命名了组合运算符,因为我的编译器被客户端代码中的另一个 operator()
蒙蔽了双眼。
它需要清理的核心在那里:
template <typename F, typename G> struct Compose
Compose( F* _f, G &_g) : f(_f), g(_g)
F* f;
G g;
double operator()(double x) return (*f)(g(x));
;
struct Base
~Base()
virtual double operator()(double x) = 0;
template <typename F> Compose<Base,F> composeMeWith(F& f) return Compose<Base,F>(this,f);
;
struct D1 : public Base
virtual double operator()(double x) return 1.0;
;
struct D2 : public Base
virtual double operator()(double x) return 2.0;
;
一些客户端代码:
#include <iostream>
using namespace std;
int main(int argc, char** argv)
D1 d1;
D2 d2;
auto ret1 = d1.composeMeWith(d2);
auto ret2 = d2.composeMeWith(d1);
cout << ret1(100.0) << endl;
cout << ret2(100.0) << endl;
【讨论】:
非常感谢!核心很重要,其余的(shared_ptr 或其他)都是微不足道的。我明天会测试它并接受(--希望 :-D)。 再次感谢,您提出的解决方案将起作用。但我很好奇是否有任何替代“指针”方法的方法?我的意思是这个任务听起来并不难:派生类只需要插入它自己的类型模板参数(这是我尝试使用 decltype(*this)...)。这是否可能仅使用基类中定义的函数? 我认为您不能在模板类型名称中引用this
(当时没有this
)。不过,您可以在
中使用它。值得调查。
@davidhigh decltype
的想法不起作用的原因在这里:***.com/questions/10424337/…【参考方案2】:
您的 Base
类是纯抽象的,因此您不能这样做。您可以将Base
类定义为具体类,然后在具体Base
类中定义重载函数调用运算符。请看下面的代码:
struct Base
~Base()
virtual double operator()(double x) const return x;
;
struct Derived1 : public Base //plus many more derived classes
;
int main()
Derived1 d;
double x = d(1);
std::cout << x << std::endl;
return 0;
【讨论】:
嗯...谢谢,但这是微不足道的。我已经编辑了我的问题,以便更清楚我想要什么。以上是关于基类中使用 this 指针的模板函数的主要内容,如果未能解决你的问题,请参考以下文章