Why doesn't the following minimal example compile with c++11
nor c++14
, but compiles in c++17
and c++2a
?
#include <iostream>
#include <limits>
#include <vector>
// works:
// static constexpr int VALUE_LIMIT_A = std::numeric_limits<int>::max();
class Classy {
// does not work in c++11 (constexpr introduced) nor c++14:
// works if c++17 or newer:
static constexpr int VALUE_LIMIT_A = std::numeric_limits<int>::max();
int VALUE_LIMIT_B = std::numeric_limits<int>::max();
public:
explicit Classy();
std::vector<int> classy;
};
Classy::Classy() {
// does not work:
classy.resize(3, VALUE_LIMIT_A);
// works:
// classy.resize(3, std::numeric_limits<int>::max());
// works:
// std::cout << VALUE_LIMIT_A;
// works:
// classy.resize(3, VALUE_LIMIT_B);
}
// required in c++11 and c++14
// constexpr int Classy::VALUE_LIMIT_A;
int main() {
Classy classy{};
for (const auto& elem : classy.classy) {
std::cout << elem << ",";
}
std::cout << "\n";
}
Here is output with c++11
:
$ g++ -std=c++11 main.cpp && ./a.out
/tmp/ccon7pPo.o: In function `Classy::Classy()':
main.cpp:(.text+0x31): undefined reference to `Classy::VALUE_LIMIT_A'
collect2: error: ld returned 1 exit status
Here is output with c++17
:
$ g++ -std=c++17 main.cpp && ./a.out
2147483647,2147483647,2147483647,
Because since C++17, the definition of the constexpr static data member at namespace scope is not required again.
If a const
non-inline (since C++17)
static data memberor a constexpr static data member (since C++11)
is odr-used, a definition at namespace scope is still required, but it cannot have an initializer.This definition is deprecated for constexpr data members (since C++17).
struct X { static const int n = 1; static constexpr int m = 4; }; const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used const int X::n; // … so a definition is necessary constexpr int X::m; // … (except for X::m in C++17)
If a static data member is declared
constexpr
, it is implicitlyinline
and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated. (since C++17)
And note that std::vector::resize
takes the 2nd parameter by reference; which cause VALUE_LIMIT_A
to be odr-used for classy.resize(3, VALUE_LIMIT_A);
.
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