为了账号安全,请及时绑定邮箱和手机立即绑定

C ++静态多态性(CRTP)并使用派生类中的typedef

C ++静态多态性(CRTP)并使用派生类中的typedef

C++
Helenr 2019-09-21 15:20:10
我阅读了Wikipedia上有关C ++中反复出现的模板模式的信息,该模板模式用于执行静态(阅读:编译时)多态性。我想对其进行概括,以便可以根据派生类型更改函数的返回类型。(这似乎应该可行,因为基本类型从template参数知道派生类型)。不幸的是,以下代码无法使用MSVC 2010进行编译(我现在无法轻松访问gcc,因此我还没有尝试过)。有人知道为什么吗?template <typename derived_t>class base {public:    typedef typename derived_t::value_type value_type;    value_type foo() {        return static_cast<derived_t*>(this)->foo();    }};template <typename T>class derived : public base<derived<T> > {public:    typedef T value_type;    value_type foo() {        return T(); //return some T object (assumes T is default constructable)    }};int main() {    derived<int> a;}顺便说一句,我有一个使用额外模板参数的解决方法,但是我不喜欢它-当在继承链中传递许多类型时,它将变得非常冗长。template <typename derived_t, typename value_type>class base { ... };template <typename T>class derived : public base<derived<T>,T> { ... };编辑:MSVC 2010在这种情况下给出的错误消息是 error C2039: 'value_type' : is not a member of 'derived<T>'g ++ 4.1.2(通过codepad.org)说error: no type named 'value_type' in 'class derived<int>'
查看完整描述

3 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

derivedbase在基类列表中将其用作模板参数时,它是不完整的。


常见的解决方法是使用特征类模板。这是您的示例,特征化。这显示了如何通过特征使用派生类中的类型和函数。


// Declare a base_traits traits class template:

template <typename derived_t> 

struct base_traits;


// Define the base class that uses the traits:

template <typename derived_t> 

struct base { 

    typedef typename base_traits<derived_t>::value_type value_type;

    value_type base_foo() {

        return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));

    }

};


// Define the derived class; it can use the traits too:

template <typename T>

struct derived : base<derived<T> > { 

    typedef typename base_traits<derived>::value_type value_type;


    value_type derived_foo() { 

        return value_type(); 

    }

};


// Declare and define a base_traits specialization for derived:

template <typename T> 

struct base_traits<derived<T> > {

    typedef T value_type;


    static value_type call_foo(derived<T>* x) { 

        return x->derived_foo(); 

    }

};

您只需要专门base_traits用于模板参数derived_t的任何类型,base并确保每个专门化都能提供所需的所有成员base。


查看完整回答
反对 回复 2019-09-21
?
海绵宝宝撒

TA贡献1809条经验 获得超8个赞

使用特征的一个小缺点是您必须为每个派生类声明一个。您可以像这样编写一个不太冗长和繁琐的解决方法:


template <template <typename> class Derived, typename T>

class base {

public:

    typedef T value_type;

    value_type foo() {

        return static_cast<Derived<T>*>(this)->foo();

    }

};


template <typename T>

class Derived : public base<Derived, T> {

public:

    typedef T value_type;

    value_type foo() {

        return T(); //return some T object (assumes T is default constructable)

    }

};


int main() {

    Derived<int> a;

}


查看完整回答
反对 回复 2019-09-21
?
慕斯王

TA贡献1864条经验 获得超2个赞

在C ++ 14中,您可以删除typedef和使用函数auto返回类型推导:


template <typename derived_t>

class base {

public:

    auto foo() {

        return static_cast<derived_t*>(this)->foo();

    }

};

之所以可行,是因为将归还类型的推导base::foo延迟到derived_t完成为止。


查看完整回答
反对 回复 2019-09-21
  • 3 回答
  • 0 关注
  • 606 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信