2012-04-29 35 views
8

关于CRP如果我要实现它(使用模板的模板参数)有轻微的变化,我得到一个编译错误:奇怪的循环模板 - 变化

template <template <typename T> class Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived* pT = static_cast<Derived*> (this); 
     pT->Action(); // instantiation invocation error here 
    } 
}; 

template<typename T> 
class Derived: public Base<Derived> 
{ 
public: 
    void Action() 
    { 
    } 
}; 

我不完全相信人会选择这种形式(无法编译对我来说),而不是使用这虽然(这个工程)

template <typename Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived* pT = static_cast<Derived*> (this); 
     pT->Action(); 
    } 
}; 

template<typename T> 
class Derived: public Base<Derived<T>> 
{ 
public: 
    void Action() 
    { 
    } 
}; 

回答

11

这也应该编译。我们只需要得到明确指定其他模板参数

template <typename T, template <typename T> class Derived> 
class Base 
{ 
public: 
    void CallDerived() 
    { 
     Derived<T>* pT = static_cast<Derived<T>*> (this); 
     pT->Action(); // instantiation invocation error here 
    } 
}; 

template<typename T> 
class Derived: public Base<T,Derived> 
{ 
public: 
    void Action() 
    { 
    } 
}; 
+1

非常有趣的一个必须在声明中明确指出typename T两次...不明白为什么 – Ghita

+1

刚刚意识到派生必须传递它的T参数。 – Ghita

5

在第一个例子中,类模板,其实需要模板的模板参数,不只是模板参数,因为你写的:

template <template <typename T> class Derived> 
class Base 
{ 
    //.. 
}; 

所以这个代码是没有意义的:

Derived* pT = static_cast<Derived*> (this); 
pT->Action(); // instantiation invocation error here 

这里Derived是一个模板,模板参数,它需要你没有模板参数提供给它。事实上,在CallDerived()函数中,您无法知道需要提供给它的类型,以便执行您打算执行的操作。

第二种方法是正确的解决方案。用它。

+1

但我怎么提供模板参数在第一种情况下..使用衍生 * PT无法正常工作或 – Ghita

+1

@Ghita:'T'没有已知基类。其他解决方案已经解释了如何将'T'传递给基地。但这不是必要的,因为你应该去寻找第二个解决方案。 – Nawaz

+1

有时在基类中需要T。例如。当有一个成员'T Action();'当然,你可以使用一个traits类为每个Derived类提供一个T,但有时候你希望T和Derived独立变化。在这种情况下,您需要使用模板+模板参数的[第一种]方法。 – TemplateRex