1

以下代码片段只有在优化级别高于 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/3dv7p

使用 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,即使它没有定义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();}
4

0 回答 0