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;
};
因此,我可能已经发现,'::'运算符的作用是以某种方式将较早执行的操作的内容(N *阶乘)馈入/添加到'value'变量中。但是有人可以更详尽地解释这一点吗(我不介意对'::'运算符角色的完整解释)。
非常感谢您!
答案 0 :(得分:6)
::
运算符称为范围解析运算符。它“解析”或明确了右侧操作数(变量名)所在的范围。
例如,std::cout
使编译器清楚知道应该在名称空间cout
中搜索标识符std
。在您的情况下,Factorial<N - 1>::value
清楚地表明value
是模板类Factorial<N - 1>
的成员。之所以使用它,是因为value
是该类的static
字段。
答案 1 :(得分:4)
所以我可能已经知道了
我强烈建议从书中学习 C ++,并学习使用现有的参考资料,而不是试图从基本原理中弄清楚某些代码的含义。如果您只是进行有根据的猜测,您很可能会犯一些细微的错误。
表达式Factorial<N - 1>::value
是qualified identifier。
Factorial<N - 1>
是类的名称(Factorial<int>
模板的实例化,其中单个参数具有特定值)。此类具有名为value
的数据成员。需要明确资格,因为此特殊 value
不在范围之内。另请参见qualified name lookup。
您可以对任何类成员使用::
这样的内容:例如std::string::npos
大致意味着在以下位置的npos
类中查找名为string
的数据成员名为std
的命名空间。
...以某种方式将先前执行的操作的内容馈入/添加到“ value”变量中...
没有“更早的版本”,所有这些都发生在编译的同一阶段。
例如,我可以手动编写
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
,这意味着我们现在有了一个等效的具体非模板类Factorial<3>
到我在上面手动编写的F_3
。
此类的定义引用Factorial<N-1>::value
(带有N-1 = 2
),因此Factorial<2>
也被实例化。这一系列隐式实例化一直持续到我们到达显式专用的Factorial<0>
为止(否则,它将一直尝试实例化Factorial<-1>
,Factorial<-2>
,直到编译器放弃并失败为止。
答案 2 :(得分:2)
如果您的类foo
具有静态成员bar
,那么您可以refer to it with the ::
notation作为foo::bar
。
在这里,Factorial<N - 1>
是一个类,具有静态成员value
。从模板符号来看,没有区别。
答案 3 :(得分:1)
struct Factorial
模板类从value
解析struct Factorial<N - 1>
,每次value
都递归解析。最后,根据以下基本情况,value
将是1
:
template <>
struct Factorial<0>
value
在这里确定:
Factorial<5> f;
std::cout << f.value << std::endl;
因此,输出将为:120
答案 4 :(得分:1)
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>
都是类。
::
是作用域解析运算符,它告诉编译器您要访问其左侧类(或名称空间)的成员(在这种情况下为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'
}
答案 5 :(得分:1)
为更清楚起见,请考虑对数据成员vector<bool>
的替代访问。
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>().value
。
因此,要指定对数据成员Factorial<12>().value
(特别是对于非静态数据成员)的访问,您可以创建类型为value
或Factorial <12>的对象。
但是静态数据成员不需要创建该类的对象。因此,使用类名和运算符::指定对静态数据成员的访问更加简单安全。
成员访问表达式Factorial<N - 1>
指定Factorial<N - 1>::value
是类value
的静态数据成员。类Factorial<N - 1>
的两个对象都不是必需的。指定静态数据成员所属的类的名称就足够了。
答案 6 :(得分:-3)
“ ::-operator”用于访问名称空间(std :: string)中的内容或类中的静态内容:
struct C {
static int i = 42;
};
int main() {
std::cout << C::i << '\n';
}
这里C :: i是静态的,所以我不需要C类的实例。要访问类内部的一些非静态内容,请使用“。”。在您的示例中,Factorial不是类而是模板,Factorial是类,而Factorial :: value是Factorial类内部的静态int值。