任何人都可以解释为什么以下代码无法编译?至少在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 :(得分:189)
您需要在某处(在类定义之后)实际定义静态成员。试试这个:
class Foo { /* ... */ };
const int Foo::MEMBER;
int main() { /* ... */ }
那应该摆脱未定义的引用。
答案 1 :(得分:71)
问题来自于新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;
}
这是因为某个实际对象的某个值存储在其中。但是,如果切换到指定静态const成员的新方法(如上所述),则Foo::MEMBER
不再是对象。这是一个常数,有点类似于:
#define MEMBER 1
但没有预处理器宏(并且具有类型安全性)的头痛。这意味着期望参考的向量不能得到一个。
答案 2 :(得分:58)
如果以某种方式需要定义,则C ++标准需要静态const成员的定义。
该定义是必需的,例如,如果使用了它的地址。 push_back
通过const引用获取其参数,因此编译器需要您的成员的地址,您需要在命名空间中定义它。
当你明确地施放常量时,你正在创建一个临时的,这是临时的,它绑定到引用(在标准中的特殊规则下)。
这是一个非常有趣的案例,我实际上认为值得提出一个问题,以便将std更改为对您的常量成员具有相同的行为!
虽然,以一种奇怪的方式,这可以被视为合法使用一元'+'运算符。基本上unary +
的结果是一个rvalue,所以rvalues绑定到const引用的规则适用,我们不使用静态const成员的地址:
v.push_back( +Foo::MEMBER );
答案 3 :(得分:10)
<强> 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;
答案 4 :(得分:3)
在 C++17 中,使用 inline
变量有一个更简单的解决方案:
struct Foo{
inline static int member;
};
这是 member
的定义,而不仅仅是它的声明。与内联函数类似,不同翻译单元中的多个相同定义不会违反 ODR。不再需要为定义选择最喜欢的 .cpp 文件。
答案 5 :(得分:1)
不知道为什么演员会工作,但Foo :: MEMBER直到第一次加载Foo时才会被分配,而且由于你从未加载它,所以它永远不会被分配。如果你在某个地方引用了Foo,它可能会有效。
答案 6 :(得分:0)
关于第二个问题:push_ref将reference作为参数,并且您不能引用类/ struct的static const memeber。调用static_cast后,将创建一个临时变量。并且可以传递对该对象的引用,一切正常。
或至少我的同事解决了这个问题。
答案 7 :(得分:0)
使用C ++ 11,上面的基本类型可以作为
class Foo {
public:
static constexpr int MEMBER = 1;
};
constexpr
部分创建静态表达式而不是静态变量 - 其行为就像一个非常简单的内联方法定义。不过,这种方法在模板类中使用C-string constexprs时有点摇摆不定。