对于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'前缀。
答案 0 :(得分: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;
答案 1 :(得分:2)
隐式实例化类不会实例化其成员函数定义。只有在使用时才会实例化类模板的每个成员(除非您使用显式实例化)。
您隐式实例化的第一件事是TDerived<int>
,位于main
的第一行。为了实例化,编译器查找TDerived
模板,发现有几个依赖的基类,所以尝试实例化它们。 TBase<int>
实例化没有问题。但是在尝试实例化THelper< TDerived<int>, TTraitsBase< TBase<int> > >
时,尝试获取成员TDerived<int>::T
,但TDerived<int>
仍然是不完整的类型。
实例化THelper< ... >
还注意到存在成员函数int Foo()
,但不评估其定义的语义。
当您从lObj.Foo()
致电main
时,int THelper< ... >::Foo()
实例化TDerived<int>
,{{1}}是完整类型,因此没有任何问题。
答案 2 :(得分: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>!
};