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

C++: recursive dependency in type alias

本文关键字:递归 依赖 关系 类型 别名 C++      更新时间:2023-10-16

我想知道以下代码是否正确。它可以在我的计算机上编译和运行,但我觉得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;
}

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

您在内部添加了一个名为ShowValueClass的类型别名这一事实ValueClass引用tmp::ShowValueClass<ValueClass>没有任何改变。在该上下文中,类的行为就像命名空间一样。

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

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

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

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


// 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取决于扩展到B::valA<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(含)的所有数字的总和。