typedef 上与 CRTP 相关的编译器错误
我想,关于 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* > (这个)->mVal
?我认为,这与实例化TDerived
时无法实例化THelper
有关,但没有明确的理解。有人可以对这里发生的事情给出简短的解释和/或一些参考吗?谢谢。
编辑:删除了“_T”前缀。
I have rather simple, I imagine, question about CRTP, but I cannot seem to find an answer to it. Probably, because it is so simple, no one thought of asking it. I am new to the concept, so, please don't laugh too hard ;).
Here is the code (it's sort of an attempt to do something similar to STL containers):
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;
}
Everything compiles if I comment the offending typedef typename _THelpee::T Th;
. And that what confuses me: if compiler does not like typedef typename _THelpee::T Th;
, why does it let through static_cast< _THelpee* > ( this )->mVal
? I assume, it has something to do with not being able to instantiate THelper
when instantiating TDerived
, but no clear understanding. Can someone, please, give a brief explanation and/or some references on what is happening here? Thank you.
EDIT: removed '_T' prefix.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
隐式实例化类不会实例化其成员函数定义。类模板的每个成员仅在使用时才会实例化(除非您使用显式实例化)。
您隐式实例化的第一件事是
TDerived
,位于main
的第一行。为了实例化它,编译器会查找TDerived
模板,发现有几个依赖基类,因此尝试实例化它们。TBase
实例化没有问题。但在尝试实例化THelper< TDerived、TTraitsBase< TBase> >
,尝试获取成员TDerived::T
,但TDerived
仍然是不完整类型。实例化
THelper< ... >
还注意到有一个成员函数int Foo()
,但不评估其定义的语义。当您从
main
调用lObj.Foo()
时,它会实例化int THelper
... >::Foo()
,TDerived
是一个完整的类型,所以那里没有问题。Implicitly instantiating a class does not instantiate its member function definitions. Each member of a class template is instantiated only when used (unless you use explicit instantiation).
The first thing you implicitly instantiate is
TDerived<int>
, on the first line ofmain
. To instantiate that, the compiler looks up theTDerived
template, sees that there are a couple of dependent base classes, so tries to instantiate those.TBase<int>
instantiates with no problem. But on trying to instantiateTHelper< TDerived<int>, TTraitsBase< TBase<int> > >
, there's an attempt to get a memberTDerived<int>::T
, butTDerived<int>
is still an incomplete type.Instantiating
THelper< ... >
also notes that there is a member functionint Foo()
, but does not evaluate the semantics of its definition.By the time you call
lObj.Foo()
frommain
, which instantiates thatint THelper< ... >::Foo()
,TDerived<int>
is a complete type, so there's no problem there.发布的代码有几个问题。由于我无法弄清楚其意图,因此我将列出我发现错误的内容。
(1) 使用不完整类型:
IMO,当您定义
TDerived<_T>
的主体时,不应使用与任何东西的参数。(2) 类型定义不当。
应该是
There are couple of problem with the code posted. Since, I couldn't make out the intention, I will list what I found erroneous.
(1) Using an incomplete type:
IMO when you are defining the body of
TDerived<_T>
, you should not use the same as a parameter to anything.(2) Improper type definition.
should be,
我想说你的 CRTP 中有一个循环依赖(正如其本质一样),但这意味着基模板类不允许使用其任何参数类,因为该参数类尚未定义 - 在实例化
Base
时它仍然是一个不完整的类型。所以,这是可以的:
但这不是:
I'd say you have a circular dependency in your CRTP (as one would have, by its very nature), but that means that the base template class isn't allowed to use any of its parameter class, because that very parameter class isn't defined yet - it's still an incomplete type at the time where
Base<T>
is instantiated.So, this is OK:
But this isn't: