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:
-3
-3
-3
Compiling with C++11 or C++14, however, leads to a linker error:
/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. If there is a cast to double(a) or even to double and back to int (c), the code runs as expected.
How can this behaviour be explained?
Until C++11 the signature of std::vector::resize() was
void resize( size_type count, T value = T() );
Now it is instead
void resize( size_type count, T const& 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. Casting to double then back to int yields a temporary in a way that avoids ODR-use; 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.
The usual fix here is to provide a definition for 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+:
b.resize(10, +aClass::HALLO);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With