C++ 静态模板类成员变量:C++ 头单元中不允许使用非内联外部定义

问题描述 投票:0回答:1

我想启动一个使用模块的新项目,因此必须将仅包含头文件的库放入头文件单元中。其中之一(sol2)在使用 Clang 编译时触发了错误(标题中的错误)。我能够在较小的头文件上重现该错误,结果发现该错误仅在使用 Clang 编译时发生:将文件编译为头单元时,GCC 没有看到问题(代码将在下面)。

现在,我知道两个编译器中的标头单元支持都是实验性的。我的问题是:完成时,哪个行为是正确的?我的印象是静态模板类成员变量应该自动标记为内联,但看起来 Clang 不同意?我期望该变量在这里被视为内联是错误的,还是 Clang 错误?

有问题的测试头文件:

#pragma once

template <typename T> struct S { static int v; };
template <typename T> int S<T>::v = 10;

template <typename T> bool b() {
    bool b1 = S<T>::v == 10;
    return b1 && true;
}

inline bool B = b<int>();

预编译成标头单元

[clan]g++ -std=c++23 -fmodule-header -xc++-user-header temp.hh

GCC 不会发出任何错误。叮当声发出:

./temp.hh:5:33: error: non-inline external definitions are not permitted in C++ header units
5 | template <typename T> int S<T>::v = 10;
  |                                 ^
./temp.hh:8:21: note: in instantiation of static data member 'S<int>::v' requested here
8 |     bool b1 = S<T>::v == 10;
  |                     ^
./temp.hh:12:17: note: in instantiation of function template specialization 'b<int>' requested here
12 | inline bool B = b<int>();
   |                 ^
1 error generated.
templates module c++20 inline header-files
1个回答
0
投票

不,这个成员变量不是内联的。函数模板也会发生类似的情况,它们不是隐式内联(请参阅在模板中使用内联关键字是否有意义?)。对头文件的简单修改揭示了潜在的多重定义错误:


    #pragma once
    
    template <typename T>
    struct S { static int i; };
    
    template <typename T> int S<T>::i = 10;
    template <> int S<int>::i = 10;

    /usr/bin/ld: /tmp/ccLUB00S.o:(.data+0x0): multiple definition of `S<int>::i'; /tmp/ccAQtrFM.o:(.data+0x0): first defined here

附注不过,我仍然想不出这可以与

inline
一起使用的情况。当然,链接器错误会转化为编译器错误,那么我们现在如何使用我们的能力呢?不管怎样,这里的变量是
not
内联的,Clang是对的,GCC显然也是对的,因为可以导入的头文件显然是实现定义的:

可导入标头是实现定义的标头集的成员,其中包括所有可导入的 C++ 库标头 (16.5.1.2)。

太棒了!

© www.soinside.com 2019 - 2024. All rights reserved.