[英]G++ (C++14) linker error on working C++03 code
Consider the following piece of code. 考虑下面的代码。
class aClass
{
public:
static const int HALLO = -3;
};
int main()
{
std::vector<double > a;
std::vector<int> b;
std::vector<int> c;
int d = aClass::HALLO; //fine
a.resize(10,aClass::HALLO); //fine
b.resize(10,aClass::HALLO); // linker error c++11 and c++14
c.resize(10,(int)(double)aClass::HALLO); //fine
std::cout<<a[0]<<endl;
std::cout<<b[0]<<endl;
std::cout<<c[0]<<endl;
return 0;
}
Compiling works with C++03 and yields the output: 编译使用C ++ 03并产生输出:
-3
-3
-3
Compiling with C++11 or C++14, however, leads to a linker error: 但是,使用C ++ 11或C ++ 14进行编译会导致链接器错误:
/tmp/cc3BARzY.o: In Funktion `main':
main.cpp:(.text+0x66): Nicht definierter Verweis auf `aClass::HALLO'
collect2: error: ld returned 1 exit status
Weirdly enough, this only happens for vector b
. 奇怪的是,这仅发生在向量
b
。 If there is a cast to double( a
) or even to double and back to int ( c
), the code runs as expected. 如果强制转换为double(
a
)甚至是double并返回int( c
),则代码将按预期运行。
How can this behaviour be explained? 如何解释这种行为?
Pre-C++11 the signature of std::vector::resize()
was 在C ++ 11之前,
std::vector::resize()
的签名为
void resize( size_type count, T value = T() );
Now it is instead 现在是
void resize( size_type count, const value_type& value );
The change from pass-by-value to pass-by-const-ref causes the callsite to ODR-use aClass::HALLO
where previously it did not. 从值传递到常量引用的更改导致呼叫站点使用
aClass::HALLO
HALLO进行ODR ,而以前则没有。 Casting to double
then back to int
yields a temporary in a way that avoids ODR-use; 转换成
double
然后返回int
可以避免ODR的使用,从而产生一个临时值。 the call to a.resize()
works for the same reason, as the int
value is implicitly cast to a double
and the argument reference is bound to the resulting temporary. 调用
a.resize()
的原因相同,因为将int
值隐式转换为double
,并将参数引用绑定到结果临时字段。
The usual fix here is to provide a definition for aClass::HALLO
; 通常的解决方法是为
aClass::HALLO
提供定义 ; if for some reason that's undesirable for you, a shorthand for yielding a temporary to avoid ODR-use is to apply unary operator+
: 如果由于某种原因您不希望使用此方法,则可以使用一元运算
operator+
来产生临时避免ODR的捷径:
b.resize(10, +aClass::HALLO);
The reason why it works for double
vector, but not int
is funny. 它适用于
double
向量而不是int
原因很有趣。 The signature for std::vector::resize
is void resize(size_type count, const value_type& value )
since C++11. 从C ++ 11开始,
std::vector::resize
的签名为void resize(size_type count, const value_type& value )
。 Taking a reference to the object makes it ODR-used, and because of that, your static int
member now needs to be defined somewhere in your application. 对对象的引用使其成为ODR使用,因此,现在需要在应用程序中的某个位置定义静态
int
成员。
However, when you std::vector<double>
, you can't bind a reference to the object. 但是,当您使用
std::vector<double>
,无法将引用绑定到该对象。 Instead, compiler creates a temporary double
object and bind the reference to said temporary. 而是,编译器创建一个临时的
double
对象,并将引用绑定到该临时对象。 Because of that, you avoid ODR-using the static member of the class, as creating a double
temporary doesn't ODR-use it, and ODR-using temporary is fine. 因此,您避免使用类的静态成员进行ODR,因为创建一个
double
临时不使用它的ODR,并且使用ODR的临时也是可以的。
Fixing the issue is trivial if you have .cpp file for the class, in which case you simply define your static there. 如果您有该类的.cpp文件,则解决此问题很简单,在这种情况下,您只需在其中定义静态即可。 However, for header-only class the solution is not trivial until C++17, where you can have inline variables and have a very nice solution:
但是,对于仅标头类,该解决方案在C ++ 17之前并不简单,在C ++ 17中,您可以具有内联变量并具有非常好的解决方案:
#include <vector>
class aClass
{
public:
static const int HALLO;
};
inline const int aClass::HALLO = -3;
int main()
{
std::vector<int> b;
b.resize(10,aClass::HALLO); //fine
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.