The following code snippet can only be linked if optimization level was higher than O0:
#include <cstdio>
#include <utility>
void vf(std::size_t n, ...) {printf("%zu\n", n);}
template<typename ...ARGS> void vt(ARGS&&... args) {vf( sizeof...(ARGS), std::forward<ARGS>(args)... );}
struct X {static constexpr int a = 123; X() {vt(a);}};
int main() {X();}
You can run it here: http://cpp.sh/3dv7p
Configuring C++11/14 with O0 will fail with the following linker error:
/tmp/cc1xC4HI.o: In function `X::X()':
:(.text._ZN1XC2Ev[_ZN1XC5Ev]+0xd): undefined reference to `X::a'
collect2: error: ld returned 1 exit status
Choosing O1, O2 or O3 will link successfully and the program execution returns the expected output.
Solution
It was shown that this problem is not related to the variadic template function. The only question is, if the compiler optimization substituted the static constexpr
member during compile time (>O0) or during link time (O0). In the later case, the declaration of X::a
also requires some valid definition. This can be done by adding constexpr int X::a;
to the above code snippet. The resulting code snippet then will link with any optimization level:
#include <cstdio>
#include <utility>
void vf(std::size_t n, ...) {printf("%zu\n", n);}
template<typename ...ARGS> void vt(ARGS&&... args) {vf( sizeof...(ARGS), std::forward<ARGS>(args)... );}
struct X {static constexpr int a = 123; X() {vt(a);}};
constexpr int X::a;
int main() {X();}
Please notice that with static constexpr
members it is necessary to initialize during declaration, to have complete type, and not during definition.
To let the compiler substitute already during compile-time, also with O0, no reference to X::a
should be passed. That's why this snippet will also successfully link with O0, even if it has no definition of X::a
:
#include <cstdio>
#include <utility>
void vf(std::size_t n, ...) {printf("%zu\n", n);}
template<typename ...ARGS> void vt(ARGS... args) {vf( sizeof...(ARGS), std::forward<ARGS>(args)... );}
struct X {static constexpr int a = 123; X() {vt(a);}};
int main() {X();}