的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 >
{
};
UPDATE:基於https://stackoverflow.com/a/11571808/819272的討論,我才發現,原來答案只能在Visual Studio 2010中編譯,但不在gcc上,因爲一些微軟特定的非便攜式功能。例如。 enable_down_cast
中的self()
函數是其派生類中的(模板)相關名稱,因此在沒有顯式using
指令時不可見。此外,我添加了默認的破壞程序,具有適當的保護級別。最後,我將原始類enable_crtp
更名爲enable_down_cast
,因爲這正是它的作用:手動啓用靜態多態,編譯器自動爲動態多態性啓用。
我一直希望避免派生的2解決方案。我正在組合一個模塊化攝像頭對象,允許策略混合搭配鏡頭,推車等。我希望能夠將變焦鏡頭指定爲焦距min和焦距max,即攝像機>,但鏡頭作爲回報,需要訪問攝像頭來調用其他模塊的功能。 (其實在鏡頭的情況下,它不是,但是在他們所做的Dolly和Heads中。) –
Tavison
2012-07-18 19:21:51
@Tavison對於基於策略的設計,您並不總是需要CRTP。例如。你可以直接從每個策略派生出來:'template class Camera:public ZoomPolicy,pubic DolliesPlicy {};'相反,你可以讓每個'ConcreteZoomPolicy'派生自一個特定的'ZoomInterface'等。 –
TemplateRex
2012-07-18 19:42:16
@ Tavison要繼續,可以使用'template class ZoomInterface:private enable_crpt > {};'然後像'template class ZoomImpl:public ZoomInterface {};'。然後你可以有一個'相機>' –
TemplateRex
2012-07-18 19:49:29