【问题标题】:What does the :: operator do in this situation:: 操作符在这种情况下做了什么
【发布时间】:2019-07-19 13:54:12
【问题描述】:
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 * 阶乘)输入/添加到“值”变量中。但是有人可以更彻底地解释这一点(我不介意对'::'操作员角色的完整解释)。

非常感谢!

【问题讨论】:

  • :: 运算符在所有情况下都执行相同的操作。它从左边的名字里面访问右边的名字。
  • related/dupe: stackoverflow.com/questions/3082113/… 它解释了这里发生的事情,而不是 :: 是什么
  • @NathanOliver 代码是同一个问题是不同的,所以不是骗子。
  • @NathanOliver 和 Marek R,我实际上发现其他线程很有用,因为我仍在尝试回溯该算法所暗示的内容(不是实际算法,而是 ' value' 变量正在被实例化和更新)。干杯!

标签: c++ templates static-methods template-meta-programming


【解决方案1】:

所以我可能已经想通了

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

表达式Factorial&lt;N - 1&gt;::value 是qualified identifier。

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

您可以将:: 像这样用于任何类成员:例如std::string::npos 大致意味着在名为string 的类中找到名为npos 的数据成员在名为std 的命名空间中 em>。

...以某种方式将之前执行的操作的内容提供/添加到“值”变量中...

没有“更早”,这一切都发生在编译的同一阶段。

比如我可以手动写

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&lt;3&gt; 实例化模板Factorial&lt;int N&gt; 为N=3,这意味着我们现在有一个具体的非模板类Factorial&lt;3&gt; 相当于我手动编写的F_3以上。

这个类的定义引用了Factorial&lt;N-1&gt;::value(和N-1 = 2),所以Factorial&lt;2&gt;也被实例化了。这条隐式实例化链一直持续到我们到达显式专门化的Factorial&lt;0&gt;(没有它,它会一直尝试实例化Factorial&lt;-1&gt;、Factorial&lt;-2&gt;,直到编译器放弃并失败)。

【讨论】:

  • 我同意我还有很多需要学习的地方,我还要感谢你的主管回复。
  • 另外,“早期”是指之前在代码中所写的;我不希望它被解释为经过一段时间。
【解决方案2】:

:: 运算符称为范围解析运算符。它“解析”或明确了右侧操作数(变量名)所在的范围。

例如,std::cout 向编译器明确指出,应在命名空间 std 中搜索标识符 cout。在您的情况下,Factorial&lt;N - 1&gt;::value 清楚地表明value 是模板类Factorial&lt;N - 1&gt; 的成员。在这里使用它是因为value 是该类的static 字段。

【讨论】:

    【解决方案3】:

    如果您有一个类foo 和一个静态成员bar,那么您可以将refer to it with the :: notation 用作foo::bar。

    这里,Factorial&lt;N - 1&gt; 是一个类,具有一个静态成员 value。除了模板符号之外,没有区别。

    【讨论】:

      【解决方案4】:
      static const int value = N * Factorial<N - 1>::value
      

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

      Factorial&lt;N&gt; 和 Factorial&lt;N-1&gt; 都是类。

      :: 是作用域解析运算符,它告诉编译器您要访问它左侧的类(或命名空间)的成员(在本例中为 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】:

        为了更清楚,考虑对数据成员 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&lt;N - 1&gt;().value 或Factorial&lt;12&gt;().value。

        因此,要指定对数据成员 value(尤其是非静态数据成员)的访问权限,您需要创建 Factorial&lt;N - 1&gt; 或 Factorial 类型的对象。

        但是静态数据成员不需要创建类的对象。因此使用类名和操作符 :: 来指定对静态数据成员的访问更加简单和安全。

        成员访问表达式Factorial&lt;N - 1&gt;::value 指定value 是类Factorial&lt;N - 1&gt; 的静态数据成员。 Factorial&lt;N - 1&gt; 类的对象都不是必需的。指定静态数据成员所属的类名即可。

        【讨论】:

          【解决方案6】:

          struct Factorial 模板类从 struct Factorial&lt;N - 1&gt; 解析 value 并且每次 value 递归解析。最后,value 将是来自以下基本情况的1:

          template <>
          struct Factorial<0>
          

          value 在这里确定:

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

          所以,输出将是:120

          【讨论】:

          • 不再不正确。让我收回我以前的 cmets。
          • 请不要像您在此处那样自动批准将代码转换为 sn-p 的 bad 编辑:stackoverflow.com/review/suggested-edits/23586198 .. OP 使用的是 SASS 代码,它非常不好的问题使它成为一个 sn-p
          【解决方案7】:

          '::-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 值。

          【讨论】:

          • a namespace 在 C++ 中是一个独特的概念。你的意思是说范围,因为 basic_string 定义了一个类,它是一个范围而不是命名空间。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-10
          • 1970-01-01
          • 2017-12-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多