次のコード スニペットは、最適化レベルが 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();}
ここで実行できます: http://cpp.sh/3d7p
O0 を使用して C++11/14 を構成すると、次のリンカー エラーで失敗します。
/tmp/cc1xC4HI.o: In function `X::X()':
:(.text._ZN1XC2Ev[_ZN1XC5Ev]+0xd): undefined reference to `X::a'
collect2: error: ld returned 1 exit status
O1、O2、または O3 を選択すると、正常にリンクされ、プログラムの実行によって期待される出力が返されます。
解決
この問題は可変個引数テンプレート関数とは関係がないことが示されました。唯一の問題は、コンパイラの最適化がstatic constexpr
コンパイル時 (>O0) またはリンク時 (O0) にメンバーを置換したかどうかです。後者の場合、 の宣言にX::a
も有効な定義が必要です。constexpr int 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);}};
constexpr int X::a;
int main() {X();}
static constexpr
メンバーでは、定義中ではなく、宣言中に初期化して完全な型にする必要があることに注意してください。
コンパイラがコンパイル時にすでに置換できるようにするには、O0 も含めて、への参照をX::a
渡さないようにする必要があります。そのため、このスニペットは、O0 の定義がなくても O0 と正常にリンクされます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();}