这个子对象链接警告是 GCC bug 吗?

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

我收到了 GCC 的子对象链接警告,但我不明白。可以使用以下代码演示该警告。

示例.h:

#ifndef EXAMPLE_H
#define EXAMPLE_H

static constexpr int value{1};

template <auto& N> struct Base {};
struct Foo : Base<value> {};

#endif

示例.cpp:

#include "example.h"

编译它会从 GCC 中产生以下输出:

/app/example.h:7:8: error: 'Foo' has a base 'Base<value>' which has internal linkage [-Werror=subobject-linkage]
    7 | struct Foo : Base<value> {};
      |        ^~~

神箭链接: https://godbolt.org/z/M5eqz9qK6

如果我将 example.h 的内容直接放入 example.cpp 中,那么它可以正常编译。 Clang 和 msvc 不会生成相同的警告。这段代码有问题吗,或者这是 GCC 中的一个错误?

c++ gcc g++
1个回答
0
投票

这只是警告,不是错误。它是格式良好的 C++,如果您不使用

-Werror
,则可以编译。

但是,警告是合理的。

您将

Foo
的定义放入头文件中,这通常意味着它旨在包含在多个翻译单元中。

value
具有内部存储持续时间,因为它是非模板、非内联、非
extern
const 限定的变量。 (
static
是多余的。)

因此,在每个翻译单元中

value
是一个不同的对象。并且因为
Base
采用引用作为模板参数,因此
Base<value>
Base
在不同翻译单元中的不同特化,因为模板参数引用每个中的不同对象。

因此,如果您在两个不同的翻译单元中包含标头,则程序将出现未定义的行为,因为

Foo
的定义违反了单定义规则,该规则不仅要求相同的两个定义模板由完全相同的标记序列组成,而且在定义中查找的所有名称都引用每个定义中的相同实体(有一些例外情况在此不适用)。

因此,警告告诉您,您的标头永远不能包含在多个翻译单元中,而不会导致未定义的行为,这可能不是有意的。

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