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

时间:2019-01-17 19:33:14

标签: c++ templates using

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

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

1 个答案:

答案 0 :(得分:2)

这里没有递归。您的班级tmp::ShowValueClass<T>可以用于任何类型T的成员value可以由cout进行可打印的成员(具有正确的ostream& operator<<(ostream&, const T&)定义)。

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

请考虑一下,如果您从ShowValueClass中提取了ValueClass

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

using ShowValueClass = tmp::ShowValueClass<ValueClass>;

在这种情况下,您将直接在ShowValueClass中访问main(),而不是像在您的情况那样以ValueClass::为前缀。 tmp::ShowValueClass使用T::valueShowValueClass中的类型别名ValueClass都是不相关(它们没有什么特别的)。 / p>

在C ++中广泛使用类本身作为模板类的模板参数的整个想法。实际上,存在一种称为CRTP(好奇地重复模板模式)的模式,其中,一个类从模板类继承而来,使用类本身作为参数(例如,来自Wikipedia):


// 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(包括两端)的所有数字的总和。