Issue
I am getting a subobject-linkage warning with GCC that I do not understand. The warning can be demonstrated with the following code.
example.h:
#ifndef EXAMPLE_H
#define EXAMPLE_H
static constexpr int value{1};
template <auto& N> struct Base {};
struct Foo : Base<value> {};
#endif
example.cpp:
#include "example.h"
Compiling this yields the following output from 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> {};
| ^~~
Godbolt link: https://godbolt.org/z/M5eqz9qK6
If I put the contents of example.h directly into example.cpp then it compiles fine. Clang and msvc do not generate this same warning. Is there an issue with this code, or is this is a bug in GCC?
Solution
This is only a warning, not an error. It is well-formed C++ and would compile if you didn't use -Werror
.
However, the warning is reasonable.
You are putting Foo
's definition in a header file, which usually means that it is intended to be included in multiple translation units.
value
has internal storage duration, because it is a non-template, non-inline, non-extern
const-qualified variable. (The static
is redundant.)
As a consequence, in each translation unit value
is a different object. And because Base
takes a reference as template argument, then Base<value>
are different specializations of Base
in different translation units, because the template parameter references different objects in each.
Then, if you include the header in two different translation units, the program will have undefined behavior, because the definitions of Foo
violate the one-definition rule as they are, roughly said, not semantically identical. The compiler has no way to decide whether Foo
is supposed to have Base<value1>
or Base<value2>
as base class (where value1
and value2
are invented names for the two instances of value
in the different translation units).
More precisely the one-definition rule not only requires that two definitions of the same class are formed by the exact same token sequence, but also that all names looked up in the definition refer to the same entity in each definition (with some exceptions that don't apply here). In fact, that value
is used as by-reference template argument isn't even relevant. The difference in lookup, coupled with value
being odr-used is sufficient to violate ODR. (See [basic.def.odr]/13.9 for the precise rule.)
So, the warning is telling you that your header can never be included in more than one translation unit without causing undefined behavior, which likely is not intended.
Answered By - user17732522 Answer Checked By - Gilberto Lyons (WPSolving Admin)