typedef 上与 CRTP 相关的编译器错误

发布于 2024-12-01 16:10:16 字数 1468 浏览 1 评论 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* > (这个)->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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

再见回来 2024-12-08 16:10:16

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

您隐式实例化的第一件事是 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 of main. To instantiate that, the compiler looks up the TDerived 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 instantiate THelper< TDerived<int>, TTraitsBase< TBase<int> > >, there's an attempt to get a member TDerived<int>::T, but TDerived<int> is still an incomplete type.

Instantiating THelper< ... > also notes that there is a member function int Foo(), but does not evaluate the semantics of its definition.

By the time you call lObj.Foo() from main, which instantiates that int THelper< ... >::Foo(), TDerived<int> is a complete type, so there's no problem there.

ぇ气 2024-12-08 16:10:16

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

(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;

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:

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

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.

using TBase< _T >::T;

should be,

typedef typename TBase< _T >::T T;
旧时光的容颜 2024-12-08 16:10:16

我想说你的 CRTP 中有一个循环依赖(正如其本质一样),但这意味着基模板类不允许使用其任何参数类,因为该参数类尚未定义 - 在实例化 Base 时它仍然是一个不完整的类型。

所以,这是可以的:

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>!
};

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:

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

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

But this isn't:

template <typename T> struct Base
{
  T x; // need to know T, but T depends on Base<T>!
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文