Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对静态类成员的未定义引用_C++_G++ - Fatal编程技术网

C++ 对静态类成员的未定义引用

C++ 对静态类成员的未定义引用,c++,g++,C++,G++,有人能解释为什么下面的代码无法编译吗?至少在g++4.2.4上 更有趣的是,当我将成员转换为int时,为什么它会编译 #include <vector> class Foo { public: static const int MEMBER = 1; }; int main(){ vector<int> v; v.push_back( Foo::MEMBER ); // undefined reference t

有人能解释为什么下面的代码无法编译吗?至少在g++4.2.4上

更有趣的是,当我将成员转换为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;
}
#包括
类Foo{
公众:
静态常量int成员=1;
};
int main(){
向量v;
v、 向后推(Foo::MEMBER);//对'Foo::MEMBER'的未定义引用
v、 向后推((int)Foo::MEMBER);//确定
返回0;
}

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

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

const int Foo::MEMBER;

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

这应该去掉未定义的引用。

< P>问题是因为新C++特性的有趣冲突和你想做的事情。首先,让我们看一下<代码> PuxSuff< <代码>签名:

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直到第一次加载Foo时才被分配,而且因为您从未加载它,所以它从未被分配。如果你在某个地方引用了一个FO,它可能会起作用。

< P>如果需要某种定义,C++标准需要定义一个静态const成员。 定义是必需的,例如,如果使用它的地址
push_back
通过const引用获取其参数,因此严格来说,编译器需要成员的地址,您需要在名称空间中定义它

当您显式地强制转换常量时,您正在创建一个临时变量,该临时变量绑定到引用(根据标准中的特殊规则)

这是一个非常有趣的案例,我真的认为有必要提出一个问题,以便将std更改为与您的固定成员具有相同的行为

虽然,以一种奇怪的方式,这可能被视为一元“+”运算符的合法使用。基本上,
一元数+
的结果是一个右值,因此将右值绑定到常量引用的规则适用,我们不使用静态常量成员的地址:

v.push_back( +Foo::MEMBER );
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;

关于第二个问题:push_ref将引用作为参数,并且不能引用类/结构的static const memeber。调用static_cast后,将创建一个临时变量。可以传递对这个对象的引用,一切正常


或者至少我解决这个问题的同事是这么说的。

使用C++11,基本类型也可以实现上述功能

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

constexpr
部分创建了一个与静态变量相反的静态表达式,其行为就像一个非常简单的内联方法定义。不过,这种方法在模板类中使用C字符串constexpr时有点不稳定

在C++17中,使用
inline
变量有一个更简单的解决方案:

structfoo{
内联静态int成员;
};

这是
成员的定义,而不仅仅是其声明。与内联函数类似,不同翻译单元中的多个相同定义不会违反ODR。不再需要为定义选择一个最喜欢的.cpp文件。

好的一点是,内联静态常量整数初始化创建一个范围内的整数常量,您不能获取该常量的地址,而vector获取一个引用参数。这个答案只解决了问题的第一部分。第二部分更有趣:为什么添加NOP cast可以在不需要外部声明的情况下工作?我花了很长时间才弄明白,如果类定义在头文件中,那么静态变量的分配应该在实现文件中,不是头球。@shanet:说得很好——我应该在回答中提到这一点!但是,如果我将其声明为const,那么我不可能更改该变量的值吗?我编辑了这个问题,将代码缩进四个空格,而不是使用。这意味着尖括号不会被解释为HTML。您可以参考这个问题。因为C++17不需要额外的定义,请参见下面的+1。是的,对于类型为T的对象x,表达式“(T)x”可以用来绑定const ref,而普通的“x”不能。我喜欢你对“一元+”的观察!谁会想到可怜的小“一元+”真的有用处……:)想想一般情况。。。在C++中是否有其他类型的对象,它只有当它已经被定义时,它(1)可以被用作LValk,但是(2)可以被转换成一个没有定义的R值,好的问题,至少目前我不能想到任何其他的例子。这可能只是因为委员会主要是在重复使用现有的语法。@RichardCorden:一元+如何解决这个问题?@Blood HaZaRd:在右值引用之前,
push_back
的唯一过载是一个
const&
。使用该成员直接导致该成员绑定到引用,这要求该成员具有地址。但是,添加
+
会创建一个带有成员值的临时值。然后,该引用将绑定到该临时引用,而不是要求成员拥有地址。谢谢,这有助于。。。这可能符合条件,如果它还没有…还值得注意的是,MSVC接受非演员版本没有投诉。-1:这根本不是真的。当odr在某个地方使用时,仍然应该定义内联初始化的静态成员。编译器优化可能会消除链接器错误,但这不会改变这一点。在这种情况下,左值到右值的转换(由于
(int)
cast)发生在translate中
class Foo {
public:  
  static constexpr int MEMBER = 1;  
};