:: 运算符在这种情况下做什么

What does the :: operator do in this situation

template <int N>
struct Factorial {
  static const int value = N * Factorial<N - 1>::value;
};

// Base case via template specialization:

template <>
struct Factorial<0> {
  static const int value = 1;
};

所以我可能已经弄清楚这里 '::' 运算符的作用是以某种方式 feed/add 进入 'value' 变量之前执行的操作内容 (N * Factorial) .但是有人可以更彻底地解释一下吗(我不介意对“::”运算符角色的完整解释)。

非常感谢!

struct Factorial 模板 class 从 struct Factorial<N - 1> 解析 value 并且每次递归解析 value。最后 value 将是 1 来自以下基本情况:

template <>
struct Factorial<0>

这里value确定:

Factorial<5> f;
std::cout << f.value << std::endl;

因此,输出将是:120

如果您有一个 class foo 和一个静态成员 bar,那么您可以 refer to it with the :: notationfoo::bar

这里,Factorial<N - 1>是一个class,有一个静态成员value。除了模板符号外,没有区别。

:: 运算符称为作用域解析运算符。它 "resolves," 或明确表示 right-hand 操作数(变量名)所在的范围。

例如,std::cout 向编译器明确表示应该在命名空间 std 中搜索标识符 cout。在你的例子中,Factorial<N - 1>::value 清楚地表明 value 是模板化 class Factorial<N - 1> 的成员。此处使用它是因为 value 是 class.

static 字段
static const int value = N * Factorial<N - 1>::value

表示成员Factorial<N>::value的值是N乘以成员Factorial<N-1>::value的值。 (Factorial<0>::value除外,它专门提供递归基本情况

Factorial<N>Factorial<N-1>都是class。

:: 是范围解析运算符,它告诉编译器您要访问 class(或命名空间)的成员(在本例中为 static 成员)在它的左边。

一个更简单的例子:

class Foo
{
    static int x;
};

int Foo::x = 42;

int main()
{
   int y = Foo::x;  // access the member 'x' in the class 'Foo'
}

或:

#include <iostream>

int main()
{
   std::cout << "hi!\n";  // access the object 'cout' in the namespace 'std'
}

So I might have figured out that

我强烈建议从书中学习 C++,并学习使用现有的参考资料material,而不是试图从基本原理中弄清楚一些代码的含义。如果您进行有根据的猜测,您很可能会犯一些细微的错误。

表达式 Factorial<N - 1>::valuequalified identifier.

Factorial<N - 1> 是 class 的名称(Factorial<int> 模板的实例,具有单个参数的特定值)。这个 class 有一个名为 value 的数据成员。需要明确限定,因为此 particular value 不在范围内。另见 qualified name lookup.

您可以像这样对任何 class 成员使用 :::例如 std::string::npos 大致意味着 在class 在名为 std.

的命名空间中调用了 string

... somehow feed/add into the 'value' variable the content of the operation performed earlier ...

没有"earlier",这一切都发生在编译的同一阶段。

比如我可以手动写

struct F_0 { static const int value = 1; }
struct F_1 { static const int value = 1 * F_0::value; }
struct F_2 { static const int value = 2 * F_1::value; }
struct F_3 { static const int value = 3 * F_2::value; }

等等我想要的尽可能多的值。模板化版本实际上是相同的,但节省了很多输入。

具体来说,编写 Factorial<3> 实例化 模板 Factorial<int N> 用于 N=3,这意味着我们现在有一个具体的 non-template class Factorial<3>相当于我上面手动写的F_3

这个class的定义引用了Factorial<N-1>::valueN-1 = 2),所以Factorial<2>也被实例化了。这个隐式实例化链一直持续到我们到达显式特化的 Factorial<0>(否则,它会一直尝试实例化 Factorial<-1>Factorial<-2>,直到编译器放弃并失败)。

'::-operator' 用于访问命名空间 (std::string) 中的内容或 class:

中的静态内容
struct C {
    static int i = 42;
};
int main() {
    std::cout << C::i << '\n';
}

此处 C::i 是静态的,所以我不需要 class C 的实例。要访问 class 中的某些 non-static 内容,您可以使用 ' .'。在您的示例中,Factorial 不是 class 而是一个模板,Factorial 是 class 并且 Factorial::value 是 class Factorial.

中的静态 int 值

为了更清楚地考虑对数据成员的替代访问 value

#include <iostream>

template <int N>
struct Factorial {
  static const int value = N * Factorial<N - 1>().value;
};

// Base case via template specialization:

template <>
struct Factorial<0> {
  static const int value = 1;
};

int main()
{
    std::cout << Factorial<12>().value << '\n';
}

程序输出为

479001600

这里使用成员访问表达式Factorial<N - 1>().valueFactorial<12>().value.

因此,要指定对数据成员 value(尤其是 non-static 数据成员)的访问权限,您可以创建类型为 Factorial<N - 1> 或 Factorial<12> 的对象。

但是静态数据成员不需要创建 class 的对象。因此,使用 class 名称和运算符 :: 来指定对静态数据成员的访问要简单和安全得多。

成员访问表达式 Factorial<N - 1>::value 指定 value 是 class Factorial<N - 1> 的静态数据成员。 class Factorial<N - 1> 的两个对象都不是必需的。指定静态数据成员所属的 class 的名称就足够了。