如何将模板参数传递给 CRTP?
Posted
技术标签:
【中文标题】如何将模板参数传递给 CRTP?【英文标题】:How do I pass template parameters to a CRTP? 【发布时间】:2012-07-18 16:53:22 【问题描述】:在以下代码中:
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;
如何编写 CRPTInt 以便可以传入模板化参数,然后将在派生定义中继续?
谢谢,
吉姆
【问题讨论】:
【参考方案1】:CRTP 模式通常用于启用静态多态性和混合(参数化)行为的能力。为了说明两种选择,先定义一个通用模板很方便
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
;
然后你为你想要的行为类型定义一个接口类模板
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
;
要获得此接口的不同实现,只需定义不同的类,每个类都派生自FooInterface
,并将它们自己定义为奇怪地重复出现的模板参数:
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";
;
另一种方法是参数化接口的不同实现。这一次,类模板同时依赖于一个模板模板参数和一个非类型参数
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
;
然后实现是另一个类模板,它派生自接口,其自身和非类型参数作为参数
template< int X >
class BarImpl
:
public BarInterface< BarImpl, X >
private:
// implementation
friend class BarInterface< ::BarImpl, X >;
void do_bar() std::cout << X << "\n";
;
这就是你对它们的称呼:
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 >
;
更新:根据https://***.com/a/11571808/819272 的讨论,我发现原始答案仅在 Visual Studio 2010 上编译,而不是在 gcc 上编译,因为某些 Microsoft 特定的、不可移植的功能。例如。来自enable_down_cast
的self()
函数是其派生类中的(模板)依赖名称,因此如果没有明确的using
指令则不可见。此外,我添加了具有正确保护级别的默认析构函数。最后,我将原来的类 enable_crtp
重命名为 enable_down_cast
,因为这正是它的作用:手动启用静态多态性,编译器自动启用动态多态性。
【讨论】:
我希望避免派生的 2 解决方案。我正在组合一个模块化相机对象,该对象允许策略混合和匹配镜头、小车等。我希望能够将变焦镜头指定为最小焦距和最大焦距,即 Cameratemplate<typename ZoomPolicy, typename DolliesPolicy> class Camera: public ZoomPolicy, pubic DolliesPlicy ;
相反,您可以让每个 ConcreteZoomPolicy
从特定的 ZoomInterface
等派生。
@Tavison 要继续,您可以创建template<typename Impl, int Min, int Max> class ZoomInterface: private enable_crpt< Impl<Min, Max> > ;
,然后实现template<int Min, int Max> class ZoomImpl: public ZoomInterface< ZoomImpl, Min, Max > ;
。然后你可以有一个Camera< ZoomImpl<24, 70> >
我会解决这个问题并在我得到它工作时接受你的回答。我知道我需要在其中再添加一层,但没有找到。
这不能在 VC10 中编译。我得到这些错误。错误 C2923:“F”:“X”不是参数“以上是关于如何将模板参数传递给 CRTP?的主要内容,如果未能解决你的问题,请参考以下文章