【问题标题】:Template getID calling regular getID调用常规 getID 的模板 getID
【发布时间】:2019-10-29 08:51:40
【问题描述】:

我在某处看到过该代码,但我不知道它是如何工作的。请解释:( 我的猜测是模板函数正在保存其他函数的状态。

代码:

#include <iostream>

int getID() {
    static int id = 0;
    return id++;
}

template <typename T>
int getID2() {
    static int id2 = getID();
    return id2;
}

int main() {
    std::cout << getID2<int>() << std::endl;
    std::cout << getID2<int>() << std::endl;
    std::cout << getID2<double>() << std::endl;
    std::cout << getID2<double>() << std::endl;
    std::cout << getID2<int>() << std::endl;

    return 0;
}

输出:

0
0
1
1
0

【问题讨论】:

  • 应该指出,这些函数很可能按照原作者的意图进行。显然,第一个会生成不断增加的(对于所有实际目的而言都是唯一的)ID。第二个(模板)创建一系列不断增加的 ID,每个 ID 都在自己的单独范围内,从第一个版本中提取的 ID 开始。除了...除了这不是真的,因为两个计数器不同步,所以很有可能,范围将重叠。它的“有趣”之处在于,根据使用情况,它实际上可能“起作用”。

标签: c++ variables static initialization local


【解决方案1】:

每个具有自己类型的模板调用都是自己的函数。本质上,您的代码包含

int getID2_int() ..

int getID2_double() ..

作为两个独立的函数。在每个单独的函数中,您都有

static int id2

它只被初始化一次,所以 getID 被调用两次——一次来自 int 版本,一次来自 double 版本。

【讨论】:

    【解决方案2】:

    首先,不同的模板特化是不同的函数,即getID2&lt;int&gt;getID2&lt;double&gt;是不同的函数。

    当你第一次调用getID2&lt;int&gt;()时,你初始化了一个static变量

    static int id2 = getID();
    

    依次调用getID(),它初始化一个static int

     static int id = 0;
    

    并返回i++i++i 的后自增,即getID() 返回i(设置为0),然后自增i(为1);因为i 是静态的,所以它会在下一次调用getID() 时保持其值1。 返回值0存储在getID2&lt;int&gt;的静态变量id2中。

    第二次调用getID2&lt;int&gt;时,会跳过id2的初始化,getID2&lt;int&gt;只返回其值0。

    现在,当您调用 getID2&lt;double&gt; 时,id2 将使用返回值 getID() 进行初始化。然而这一次,getID() 的静态变量i 已经初始化,它等于 1。因此getID() 返回 1,并将i 递增到 2。返回值 1 传递给getID2&lt;double&gt;,它将其static int id2 变量初始化为id2=1

    在下一次调用getID2&lt;double&gt;时,id2已经初始化为1,因此getID2&lt;double&gt;只返回1。

    【讨论】:

      【解决方案3】:

      函数的静态变量只在函数第一次获得控制权时初始化一次。

      所以当函数特化getID2&lt;int&gt;第一次被调用时

      std::cout << getID2<int>() << std::endl;
      

      它的静态变量id2被非模板函数的静态变量id的值初始化为0(注意非模板函数的return语句中使用了post-递增运算符

      return id++;
      

      所以函数的返回值就是变量id在递增前的值。)

      。所以在函数模板特化的第二次调用中

      std::cout << getID2<int>() << std::endl;
      

      声明

      static int id2 = getID();
      

      被跳过,函数再次输出0

      这同样适用于函数模板特化getID2&lt;double&gt;,但在这种情况下,在函数的第一次调用中,id 的值已经更改为 1。所以所有特化调用都返回初始化的静态变量id2 的值为 1

      std::cout << getID2<double>() << std::endl;
      

      在随后的专业化调用中再次声明

      static int id2 = getID();
      

      被跳过,因为静态变量 id2 已经初始化。

      注意模板函数的特化是不同的函数。

      来自 C++ 17 标准(9.7 声明语句)

      4 使用静态存储动态初始化块范围变量 持续时间 (6.7.1) 或线程存储持续时间 (6.7.2) 第一次控制通过它的声明;这样的变量是 在其初始化完成时被认为已初始化......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-12
        • 1970-01-01
        • 2016-09-11
        • 1970-01-01
        • 2013-06-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-11
        相关资源
        最近更新 更多