如何将模板参数传递给CRTP? [英] How do I pass template parameters to a CRTP?

查看:280
本文介绍了如何将模板参数传递给CRTP?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下代码中:

  template< typename T& 
class CRTP
{
public:
};

template< int I,typename T>
class CRTPInt
{
public:
};

template< template< typename>类T>
class Derived:public T< Derived< T>>
{
public:
};

void main()
{
派生的< CRTP> foo;
派生的< CRTPInt< 2> foo2;
}

如何编写CRPTInt以便我可以传递一个模板化的参数,然后





CRTP模式通常用于启用静态多态性 mixin (参数化)行为的能力。为了说明两个选择,首先定义一个一般模板是很方便的。

  template 
<
typename衍生的
>
class enable_down_cast
{
private:
// typedefs

typedef enable_down_cast Base;

public:
派生的const * self()const
{
//转换继承继承层次结构
return static_cast< Derived const *> ;(这个);
}

//以const版本编写非const版本
// Effective C ++ 3rd ed。,Item 3(p。24-25)
Derived * self()
{
return const_cast< Derived *>(static_cast< Base const *>(this)
}

protected:
//禁用通过Base删除Derived *
//允许通过Derived删除Base *
〜enable_down_cast )= default; // C ++ 11 only,use〜enable_down_cast(){} in C ++ 98
};

然后为您想要的行为类型定义一个接口类模板

 模板< typename FX> 
class FooInterface

//启用静态多态性
public enable_down_cast< FX>
{
private:
//依赖名称现在在范围
使用enable_down_cast< FX> :: self;

public:
// interface
void foo(){self() - > do_foo(); }

protected:
//禁用通过Base *删除Derived *
//通过Derived *启用Base *的删除
〜IFooInterface()= default; // C ++ 11 only,use〜IFooInterface(){} in C ++ 98/03
};

要获得此接口的不同实现,只需定义不同的类, > FooInterface 自己作为奇怪的重复模板参数

  class FooImpl 

public FooInterface< FooImpl>
{
private:
// implementation
friend class FooInterface< FooImpl> ;
void do_foo(){std :: cout<< Foo\\\
; }
};

class AnotherFooImpl

public FooInterface< AnotherFooImpl>
{
private:
// implementation
friend class FooInterface< AnotherFooImpl> ;;
void do_foo(){std :: cout<< AnotherFoo\\\
; }
};

另一种方法是参数化接口的不同实现。这一次,类模板依赖于模板模板参数和非类型参数

  template< template< int>类F,int X> 
class BarInterface

public enable_down_cast< F X, >
{
private:
//依赖名称现在在范围
使用enable_down_cast< F X, > :: self;

public:
// interface
void bar(){self() - > do_bar(); }

protected:
//禁用通过Base *删除Derived *
//通过Derived *启用Base *的删除
〜BarInterface()= default; // C ++ 11 only,use〜BarInterface(){} in C ++ 98/03
};

实现是另一个类模板,它从自身和非类型的接口派生参数作为参数

  template< int X> 
class BarImpl

public BarInterface< BarImpl,X>
{
private:
// implementation
friend class BarInterface< :: BarImpl,X> ;;
void do_bar(){std :: cout< X<< \\\
; }
};

这就是你叫他们的方式:

  int main()
{
FooImpl f1;
AnotherFooImpl f2;
BarImpl< 1。 b1;
BarImpl< 2。 b2;

f1.foo();
f2.foo();
b1.bar();
b2.bar();

return 0;
}

问题中的类不适合这种一般模式。如果你可能想给 Derived 一些类似于CRTP的行为,你可以做

  class Derived1 

public CRTP< Derived1>
{

};

template< int I>
class Derived2

public CRTPInt< Derived2,I>
{

};

UPDATE :根据http://stackoverflow.com/a/11571808/819272 ,我发现原来的答案只是在Visual Studio 2010上编译,而不是在gcc上因为一些Microsoft特定的,非便携式功能。例如。来自 enable_down_cast self()函数是其派生类中的(模板)依赖名称,因此不可见显式使用指令。此外,我添加了默认的析构函数具有正确的保护级别。最后,我将我的原始类 enable_crtp 重命名为 enable_down_cast ,因为这正是它的作用:手动启用静态多边形编译器自动为动态多态性做什么。


In the following code:

template <typename T>
class CRTP
{
public:
};

template <int I, typename T>
class CRTPInt
{
public:
};

template <template <typename> class T>
class Derived : public T<Derived<T>>
{
public:
};

void main()
{
Derived<CRTP> foo;
Derived<CRTPInt<2>> foo2;
}

How do I write CRPTInt so I can pass in a templatized parameter that will then be continued in the Derived definition?

Thanks,

Jim

解决方案

The CRTP pattern is typically used to enable static polymorphism and the ability to mixin (parametrized) behavior. To illustrate two alternatives, it's convenient to first define a general template

template
<
        typename Derived
>
class enable_down_cast
{
private:
        // typedefs

        typedef enable_down_cast Base;

public:
        Derived const* self() const
        {
                // casting "down" the inheritance hierarchy
                return static_cast<Derived const*>(this);
        }

        // write the non-const version in terms of the const version
        // Effective C++ 3rd ed., Item 3 (p. 24-25)
        Derived* self()
        {
                return const_cast<Derived*>(static_cast<Base const*>(this)->self());
        }

protected:
        // disable deletion of Derived* through Base*
        // enable deletion of Base* through Derived*
        ~enable_down_cast() = default; // C++11 only, use ~enable_down_cast() {} in C++98
};

Then you define an interface class template for the type of behavior that you want

template<typename FX>
class FooInterface
:
    // enable static polymorphism
    public enable_down_cast< FX >
{
private:
    // dependent name now in scope
    using enable_down_cast< FX >::self;

public:
    // interface
    void foo() { self()->do_foo(); }

protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~IFooInterface() = default; // C++11 only, use ~IFooInterface() {} in C++98/03
};

To get different implementations of this interface, simply define different classes that each derive from FooInterface with themselves as curiously recurring template parameters:

class FooImpl
:
    public FooInterface< FooImpl > 
{
private:
    // implementation
    friend class FooInterface< FooImpl > ;
    void do_foo() { std::cout << "Foo\n"; }
};

class AnotherFooImpl
:
    public FooInterface< AnotherFooImpl > 
{
private:
    // implementation
    friend class FooInterface< AnotherFooImpl >;
    void do_foo() { std::cout << "AnotherFoo\n"; }
};

The alternative is to parametrize the different implementations of an interface. This time, the class template depends on both a template-template parameter and a non-type parameter

template<template<int> class F, int X>
class BarInterface
:
    public enable_down_cast< F<X> >
{
private:
    // dependent name now in scope
    using enable_down_cast< F<X> >::self;

public:
    // interface
    void bar() { self()->do_bar(); }    

protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~BarInterface() = default; // C++11 only, use ~BarInterface() {} in C++98/03
};

The implementation is then another class template, which derives from the interface with both itself and the non-type parameter as arguments

template< int X >
class BarImpl
:
    public BarInterface< BarImpl, X > 
{
private:
    // implementation
    friend class BarInterface< ::BarImpl, X >;
    void do_bar() { std::cout << X << "\n"; }    
};

This is how you call them:

int main()
{
    FooImpl f1;         
    AnotherFooImpl f2;
    BarImpl< 1 > b1;
    BarImpl< 2 > b2;

    f1.foo();
    f2.foo();
    b1.bar();
    b2.bar();

    return 0;
}

The classes in your question don't quite fit into this general pattern. If you might want to give Derived some CRTP-like behavior, then you can either do

class Derived1
: 
   public CRTP< Derived1 > 
{

};

template<int I>
class Derived2
: 
   public CRTPInt< Derived2, I >
{

};

UPDATE: Based on the discussion from http://stackoverflow.com/a/11571808/819272, I discovered that the original answer only compiled on Visual Studio 2010, but not on gcc because of some Microsoft-specific, non-portable features. E.g. the self() function from enable_down_cast is a (template) dependent name in its derived classes, and therefore not visible without explicit using directives. Furthermore, I have added defaulted destructors with the right level of protection. Finally, I have renamed my original class enable_crtp to enable_down_cast because that is precisely what it does: manually enable for static polymporphism what the compiler does automatically for dynamic polymorphism.

这篇关于如何将模板参数传递给CRTP?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆