2008-11-07 151 views
172

任何人都可以解释为什么下面的代码不能编译?至少在g ++ 4.2.4上。对静态类成员的未定义引用

更有趣的是,为什么它会在我将MEMBER投射到int时编译?

#include <vector> 

class Foo { 
public: 
    static const int MEMBER = 1; 
}; 

int main(){ 
    vector<int> v; 
    v.push_back(Foo::MEMBER);  // undefined reference to `Foo::MEMBER' 
    v.push_back((int) Foo::MEMBER); // OK 
    return 0; 
} 
+0

我编辑了这个问题,让代码缩进四个空格而不是使用

。这意味着尖括号不会被解释为HTML。 – 2008-11-07 19:03:01

+0

欢呼声:) 10个字符的最小规则有时很讨厌;) – 2008-11-08 12:30:10

回答

176

您需要在某处(类定义之后)实际定义静态成员。试试这个:

class Foo { /* ... */ }; 

const int Foo::MEMBER; 

int main() { /* ... */ } 

这应该摆脱未定义的参考。

+3

好点,内联静态常量整数初始化创建一个范围的整数常量,你不能取地址,而向量需要一个参考参数。 – 2008-11-07 18:08:07

+9

此答案只解决问题的第一部分。第二部分更有意思:为什么添加一个NOP类型可以在不需要外部声明的情况下工作? – nobar 2011-02-01 00:48:40

+27

我只花了很长时间弄清楚,如果类定义在头文件中,那么静态变量的分配应该在实现文件中,而不是头中。 – shanet 2012-07-14 03:06:28

69

问题来自于新C++特性的有趣冲突以及您正在尝试做什么。首先,让我们来看看push_back签名:

void push_back(const T&) 

该公司预计,到T类型的对象的引用。在旧的初始化系统下,存在这样的成员。例如,下面的代码编译得很好:

#include <vector> 

class Foo { 
public: 
    static const int MEMBER; 
}; 

const int Foo::MEMBER = 1; 

int main(){ 
    std::vector<int> v; 
    v.push_back(Foo::MEMBER);  // undefined reference to `Foo::MEMBER' 
    v.push_back((int) Foo::MEMBER); // OK 
    return 0; 
} 

这是因为有一个实际的对象存储了该值。但是,如果您切换到指定静态常量成员的新方法(如上所述),则Foo::MEMBER不再是对象。它是一个常数,有点类似于:

#define MEMBER 1 

但没有预处理器宏(和类型安全)的麻烦。这意味着期待参考的矢量不能得到一个。

1

不知道为什么演员会工作,但是Foo :: MEMBER在第一次加载Foo之前​​不会被分配,并且由于您从未加载Foo :: MEMBER,所以从未分配Foo :: MEMBER。如果你在某处引用了Foo,它可能会起作用。

56

如果需要定义,C++标准需要定义静态const成员。

定义是必需的,例如,如果使用的是地址。 push_back通过const引用获取其参数,因此严格地说编译器需要您的成员的地址,并且您需要在名称空间中定义它。

当您明确地转换常量时,您正在创建一个临时参数,并且它是绑定到参考的临时参数(在标准中的特殊规则下)。

这是一个非常有趣的案例,实际上我认为值得提出一个问题,以便std被更改为对于常量成员具有相同的行为!

虽然,以一种奇怪的方式,这可以被视为一元'+'运算符的合法使用。基本上unary +的结果是右值的结合为const引用适用的右值等规则,我们不使用我们的静态const成员地址:

v.push_back(+Foo::MEMBER); 
9

Aaa.h

class Aaa { 

protected: 

    static Aaa *defaultAaa; 

}; 

Aaa。CPP

// You must define an actual variable in your program for the static members of the classes 

static Aaa *Aaa::defaultAaa; 
0

关于第二个问题:push_ref需要引用作为参数,并且你不能有一类/结构的静态常量memeber参考。一旦你调用static_cast,就会创建一个临时变量。并且可以传递这个对象的引用,一切正常。

或者至少我的同事谁解决这个如此说。

1

用C++ 11,上面将基本类型是可能的

class Foo { 
public: 
    static constexpr int MEMBER = 1; 
}; 

constexpr部分创建一个静态表达,而不是静态可变 - 和行为就像一个极其简单的内联方法定义。不过,这种方法在模板类中使用C字符串constexprs证明有点不稳定。

相关问题