2012-07-18 60 views
2

在下面的代碼:如何將模板參數傳遞給CRTP?

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這樣我就可以在隨後將在導出的定義繼續一個模板化的參數傳遞?

謝謝,

吉姆

回答

3

的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,因爲這正是它的作用:手動啓用靜態多態,編譯器自動爲動態多態性啓用。

+0

我一直希望避免派生的2解決方案。我正在組合一個模塊化攝像頭對象,允許策略混合搭配鏡頭,推車等。我希望能夠將變焦鏡頭指定爲焦距min和焦距max,即攝像機>,但鏡頭作爲回報,需要訪問攝像頭來調用其他模塊的功能。 (其實在鏡頭的情況下,它不是,但是在他們所做的Dolly和Heads中。) – Tavison 2012-07-18 19:21:51

+0

@Tavison對於基於策略的設計,您並不總是需要CRTP。例如。你可以直接從每個策略派生出來:'template class Camera:public ZoomPolicy,pubic DolliesPlicy {};'相反,你可以讓每個'ConcreteZoomPolicy'派生自一個特定的'ZoomInterface'等。 – TemplateRex 2012-07-18 19:42:16

+0

@ Tavison要繼續,可以使用'template class ZoomInterface:private enable_crpt > {};'然後像'template class ZoomImpl:public ZoomInterface {};'。然後你可以有一個'相機>' – TemplateRex 2012-07-18 19:49:29