0

我想我有一个相当简单的关于CRTP的问题,但我似乎找不到答案。大概是因为太简单了,没有人想过要问。我是这个概念的新手,所以,请不要笑得太厉害;)。

这是代码(这是一种类似于 STL 容器的尝试):

template< typename tT >
struct TBase
{
  typedef tT T;
};

template< typename tTBase >
struct TTraitsBase
{
  typedef typename tTBase::T T;
};

template< typename tTHelpee, typename tTTraits >
struct THelper
{

  typedef typename tTTraits::T T;
  typedef typename tTHelpee::T Th; /* This generates a compiler error:
                                      'T' not being a member of TDerived<tT> */
  T Foo( void )
  {
   return static_cast< tTHelpee* > ( this )->mVal;
  }
};

template< typename tT >
struct TDerived : TBase< tT > , THelper< TDerived< tT > , TTraitsBase< TBase< tT > > >
{
 using TBase< tT >::T;
  T mVal;
};

int main()
{
 TDerived< int >::T lTmp = -1;
 TDerived< int > lObj;

 lObj.mVal = -1;
 std::cout << lObj.Foo() << std::endl;

 return 0;
}

如果我评论有问题,一切都会编译typedef typename _THelpee::T Th;。这让我感到困惑:如果编译器不喜欢typedef typename _THelpee::T Th;,为什么它会通过static_cast< _THelpee* > ( this )->mVal?我认为,这与实例化THelper时无法实例化有关TDerived,但没有清楚的理解。有人可以就这里发生的事情给出一个简短的解释和/或一些参考吗?谢谢你。

编辑:删除 '_T' 前缀。

4

3 回答 3

2

发布的代码有几个问题。由于我无法弄清楚意图,我将列出我发现错误的内容。

(1)使用不完整类型

template< typename _T >
struct TDerived : TBase< _T > , THelper< TDerived< _T > , TTraitsBase< TBase< _T > > >
                                         ^^^^^^^^^^^^^^ it's incomplete

IMO 在定义 的主体时TDerived<_T>,不应将其用作任何东西的参数。

(2) 类型定义不当。

using TBase< _T >::T;

应该,

typedef typename TBase< _T >::T T;
于 2011-08-29T12:03:57.807 回答
2

隐式实例化一个类不会实例化它的成员函数定义。类模板的每个成员仅在使用时才被实例化(除非您使用显式实例化)。

您隐式实例化的第一件事是TDerived<int>,在main. 为了实例化它,编译器查找TDerived模板,发现有几个依赖的基类,所以尝试实例化它们。 TBase<int>实例化没有问题。但是在尝试实例化THelper< TDerived<int>, TTraitsBase< TBase<int> > >时,会尝试获取成员TDerived<int>::T,但TDerived<int>仍然是不完整的类型。

实例化THelper< ... >还注意到有一个成员函数int Foo(),但不评估其定义的语义。

当您调用lObj.Foo()frommain时,实例化 thatint THelper< ... >::Foo()TDerived<int>一个完整的类型,所以那里没有问题。

于 2011-08-29T12:12:27.520 回答
1

我会说您的 CRTP 中有一个循环依赖项(就其本质而言),但这意味着基础模板类不允许使用它的任何参数类,因为那个参数类是'尚未定义 - 在Base<T>实例化时它仍然是一个不完整的类型。

所以,这没关系:

template <typename T> struct Base
{
  T * impl;  // incomplete type is OK
};

class Foo : public Base<Foo> { /* ... */ };

但这不是:

template <typename T> struct Base
{
  T x; // need to know T, but T depends on Base<T>!
};
于 2011-08-29T12:04:19.273 回答