未被引用类的C++静态变量

7
在下面的程序中,将打印“Here”:
#include <iostream>
class Base
{
  static bool temp;
  static bool initTemp()
  {std::cout<<"Here\n";return true;}
};

bool Base::temp = Base::initTemp();

class Derived : public Base
{};

int main() {int a;std::cin>>a;}

在下面的程序中,“Here”没有被打印出来:
#include <iostream>
template <class T>
class Base
{
  static bool temp;
  static bool initTemp()
  {std::cout<<"Here\n";return true;}
};

template <class T>
bool Base<T>::temp = Base<T>::initTemp();

class Derived : public Base<int>
{};

int main() {int a;std::cin>>a;}

在两种情况下,Base都没有被引用。唯一的区别是在第二种情况下它是一个模板类。有人能解释一下为什么会出现这种行为吗?我正在使用VS 2012。


2
void main() 不是合法的 C++ 语法。应该使用 int main() - John Dibling
在第二个例子中,如果您显式实例化静态成员,则会打印“Here”:template bool Base<int>::temp; - willj
3个回答

6
在这两种情况下,Base 都没有被引用过。
这正是您看不到任何内容被打印到标准输出的原因。
类模板静态数据成员的定义不会被实例化,除非您使用该数据成员;与成员函数一样,类模板静态数据成员的定义是按需实例化的。
这在 C++11 标准的第14.7.1/1段中有明确规定:
[...] 类模板特化的隐式实例化会导致声明的隐式实例化,但不会导致类成员函数、成员类、作用域成员枚举、静态数据成员和成员模板的定义或默认参数的实例化。[...]
由于客户端代码从未涉及 Base<>::temp,因此无需构造和初始化它。
另外,这个签名:
void main()

这不是有效的(标准)C++。如果您想编写可移植的代码,main()函数的返回类型应始终为 int


但是代码包含 class Derived : Base<int> …为什么这不算实例化? - Konrad Rudolph
我编辑了这篇文章,以便它使用int。有没有办法通过继承来实例化类?也就是说,有没有办法自动初始化许多不同派生类型的temp,而不必编写template<>bool Base<int>::temp=Base<int>::initTemp();这样的代码? - Benjy Kessler
@KonradRudolph: "类模板特化的隐式实例化会导致声明的隐式实例化,但不会导致类成员函数、成员类、作用域成员枚举、静态数据成员和成员模板的定义或默认参数的隐式实例化" (14.7.1/1) - Andy Prowl
@BenjyKessler:好的,我会编辑答案以反映您的修改。 - Andy Prowl

2
在第一种情况下,您不需要实例化 Base,但是您需要调用静态函数:
bool Base::temp = Base::initTemp();

在第二种情况下,您不需要实例化template:
template <class T>
bool Base<T>::temp = Base<T>::initTemp();

您可以显式实例化Base类模板,如下所示:

template class Base<int>;

然后你会看到打印出“Here”的内容。


好的,很酷,我不知道前置声明模板类会实例化它。 - Benjy Kessler
1
@BenjyKessler:那不是前向声明,而是显式实例化。 - Andy Prowl
@BenjyKessler:哈哈,是的,已经编辑了评论。我的大脑正在睡觉。 - Andy Prowl

-3

您似乎在以下代码行中创建了未定义类的变量:

您不能创建未定义类的变量:

template <class T>
bool Base<T>::temp = Base<T>::initTemp();

你不能分配未定义类型的变量。你需要这样写:
Base<int>::temp = value;

当然,为每个提供的类型分配不同的变量,因此您不能为模板类拥有常见的静态变量。您将为每个实例化模板的类型拥有单独的变量。
这里是完整的示例,对于那些投反对票的人:
#include <iostream>

template<class T>
class X
{
public:
    static int v;
};

template<class T>
int X<T>::v = 0;

int main()
{
    X<int>::v = 3;
    X<char>::v = 2;

    using namespace std;
    cout << X<char>::v << endl << X<int>::v;
}

它打印出2 3,这意味着您不能为所有类都使用单个变量来实例化模板。


我认为Bogolt的意思是对于X的每个不同实例,您将拥有不同的v值。这是正确的,但我希望每个实例都有不同的v值。为了在所有实例化X之间共享相同的静态变量,X应该继承一些非模板基类,其中包含v。 - Benjy Kessler
你的代码示例实际上表明了你可以做到你声称不能做到的事情。 - Konrad Rudolph
我认为,当您使用模板类的变量时,它取决于模板实例化的类型。通过创建单个变量,您实际上为每个类实例化创建了多个变量。我并没有真正看到我说相反的情况。 - Bogolt
你声称“你需要做的是写出这样的代码:Base<int>::temp = value;”,但这显然是不正确的。其余部分只是干扰。 - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接