如何在 CRTP 中推断类型

How to infer the type in CRTP?

本文关键字:类型 CRTP      更新时间:2023-10-16

我想在 c++ 模板中实现 CRTP。代码如下:

template <typename T>
class A{
public:
    typedef typename T::Scalar Scalar;
};
template <typename T>
struct B:public A<B<T> > {
public:
    typedef T Scalar;
};

但是当我编译代码时,编译器显示:

error: no type named ‘Scalar’ in ‘struct B<int>’

谁能解释一下?

该错误是由于类型不完整造成的。请看下面的行:

template<typename T>
struct B : public A<B<T>> 

B<T>的主体尚未开始,您正在将其用作构建A<T>的参数。实际上这是允许的,但正如昆汀的回答中提到的,这是CRTP的一个警告。除了这个答案,这里有另一种方式:

template <template<typename> class Base, typename T>
class A{ // use `<typename...>` for C++11
public:  
  typedef T Scalar;
  // use `Base<T>` wherever required
};
template <typename T>
struct B : public A<B, T> {
public: //        ^^^^^^^
    typedef T Scalar;
};

问题是A<T>的 API 说必须定义T::Scalar,这在template<typename U> struct B:public A<B<U> > {中还不是这样。

简单的更改是修复 A 的 API:

template <typename SCALAR>
class A{
public:
    typedef SCALAR Scalar;
};
template <typename T>
struct B:public A<T> {
};

抽象地说,A<T>, T::Scalar的使用是一种按名称传递的形式,而A<SCALAR>是常规的按参数传递。当名称尚未在您需要它们的位置定义时,按名称传递是有问题的。

[编辑]而且因为它看起来并不明显,所以您仍然可以保留 CRTP:

template <typename SCALAR, typename CRTP>
class A{
public:
    typedef SCALAR Scalar;
};
template <typename T>
struct B:public A<T, B<T>> {
};

另一种看待它的方式,

B<int> b is called which will invoke
B<int> : A<B<int> > which will further invoke // B is not yet done waiting on A<B<int> >
A<B<int>> { typedef B<int>::Scalar Scalar } will try to fetch B<int> //which is not yet constructed as many pointed out.

下面的代码不是解决方案,但会解释问题所在。下面的代码编译是因为我们打破了循环。

template <typename T>
class A{
public:
    typedef typename T::Scalar Scalar;
};
template <typename T>
class B:public A<B<T> > {
public:
    typedef T Scalar;
};
template <>
class A<B<int> > {
public :
        typedef int Scalar;
};
int main()
{
        B<int> b;
}

现在的解决方案是打破循环或避免循环。因此,我们可以想到很少的解决方案。