C++:类型别名中的递归依赖

C++: recursive dependency in type alias

我想知道下面的代码是否正确。它在我的电脑上编译和运行,但我觉得在 ValueClass 中定义了 ShowValueClass 类型别名的递归依赖。您能否解释一下编译器是如何解决它的?

#include <iostream>

namespace tmp {
template <typename T>
struct ShowValueClass {
  void ShowValue() { std::cout << T::value << std::endl; }
};
} // namespace tmp

struct ValueClass {
  using ShowValueClass = tmp::ShowValueClass<ValueClass>;
  static constexpr int value = 42;
};

int main() {
  ValueClass::ShowValueClass s;
  s.ShowValue();
  return 0;
}

这里没有递归。您的 class tmp::ShowValueClass<T> 仅适用于具有 value 成员 可打印 的任何类型 T cout(具有右ostream& operator<<(ostream&, const T&)定义)。

您在 ValueClass 中添加了一个名为 ShowValueClass 的类型别名以引用 tmp::ShowValueClass<ValueClass> 的事实没有任何改变。在这种情况下,class 就像一个命名空间。

想想如果你从ValueClass中提取ShowValueClass会发生什么:

struct ValueClass {
  static constexpr int value = 42;
};

using ShowValueClass = tmp::ShowValueClass<ValueClass>;

在那种情况下,您将直接在 main() 中访问 ShowValueClass,而不是像您的情况那样在其前面加上 ValueClass::tmp::ShowValueClass 使用 T::value 和类型别名 ShowValueClassValueClass 中的事实都是 无关的 (它们没有什么特别之处).

使用 class 本身作为模板 class 的模板参数的整个想法在 C++ 中很普遍。实际上,有一种称为 CRTP(奇怪的重复模板模式)的模式,其中 class 继承自模板 class,使用 class 本身作为参数(来自维基百科):


// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
{
    // methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
    // ...
};

您可以在此处查看整篇文章:https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

一个真正的递归依赖示例

现在,为了完成图片,我可以向您展示一些由于递归定义而无法编译的代码:

template <typename T>
struct A {
   static constexpr int val = T::val;
};

struct B {
   static constexpr int val = A<B>::val;
};

int main() { }

在这里,A<T>::val 依赖于 T::val,这没关系,但是 B::val 依赖于 A<B>::val,后者扩展为 B::val。换句话说,B::val依赖于B::val,显然无法解决。就像这样说:

x := y(x)

其中 y(x) 为:

y(x) := x. 

因此,x := x。显然,无法确定 x.

的值

使用模板递归的工作示例

现在,如果正确进行递归并且定义了 基本情况,显然它甚至可以用于计算非常复杂的事情。 这是一个简单的例子:

#include <iostream>
using namespace std;

template <int N>
struct A {
   static constexpr int val = N + A<N - 1>::val;
};

template <>
struct A<0> {
   static constexpr int val = 0;
};

int main() {
   cout << A<10>::val << endl;
}

A<N>::val 递归定义为:

N + A<N-1>::val if N != 0
0               if N == 0

因此,它是从0N(含)的所有数字的总和。