C++ – Constexpr Variable at Namespace Scope with Inline Definition

c++c++17language-lawyerone-definition-rule

Even after reading this question about non explicit inline namespace scoped variables, defined in headers, I am a bit paranoid about explicit inline namespace scope variables being ok, since AFAIK violations against the ODR are UB and not diagnosis is required. Is my understanding correct that explicitly inline specified constexpr (and const non volatile alike) defined variables at namespace scope are inline variables and therefore their ODR usage is ok when used in different translation units?
Even cppreference.com is contradicting itself, when it sometimes say inline variables have to be external for the ODR usage exception, while on another page only internal linkage inline variables are ok in general, and external only with additional requirements.

Basically are these assumptions right?:

/*! @file some_header.hpp */
#ifndef HEADER_GUARD
#define HEADER_GUARD

constexpr int global_non_expl_inline = 42; //UB
static constexpr int global_non_expl_inline_static = 42; //UB
inline int global_expl_inline = 42; //ok
inline int static global_expl_inline_explicit_static = 42; //? external linkage by default but static explicit but still ok?
inline int extern global_expl_inline_explicit_extern = 42; //UB

namespace foo {
constexpr int global_non_expl_inline = 42; //UB
static constexpr int global_non_expl_inline_static = 42; //UB
inline int global_expl_inline = 42; //ok
inline int static global_expl_inline_explicit_static = 42; //? external linkage by default but static explicit but still ok?
inline int extern global_expl_inline_explicit_extern = 42; //UB
}

namespace {
inline int extern global_expl_inline_explicit_extern_but_unnamed_ns = 42; //ok
}

struct bar{
    static int const in_class_static = 42;//ok
    static int in_class_but_out_of_source_def;
};

int bar::in_class_but_out_of_source_def = 42;//UB

#endif

Best Answer

Well... Since you actually managed to get myself confused with your question, I thought I'd look further into it. First, we have to categorize the relevant properties of a variable: lifetime, visibility, linkage These are influenced by the keywords: static, inline, constexpr, const, extern which you use in your question.

At namespace scope in variable definition:
- static: specifies internal linkage
- inline: allows for multiple identical definitions of the same variable in different translation units and ensures they will refer to the same object (e.g have the same adresses)
- constexpr: implies const - const: defaults to external linkage
- extern: specifies external linkage

Thus,
- global_non_expl_inline: defaults to external linkage. No problem, unless another translation unit defines another such variable with external linkage.
- global_non_expl_inline_static: internal linkage. Fine, as long as you do not define other such variables anywhere.
- global_expl_inline: External linkage and inline. No problems, unless another translation unit declares another such variable without inline.
- global_expl_inline_explicit_static: Fine, a static inline variable is meaningful, if you do not want it to be available at link time, but do want the same variable in all your translation units - e.g useful for all sorts of constants.
- global_expl_inline_explicit_extern: External linkage and inline. No problems, unless another translation unit declares another such variable without inline.
- global_expl_inline_explicit_extern_but_unnamed_ns: internal linkage according to cppreference.

At class scope:
- in_class_static: external linkage. Fine, according to cppreference, but needs a declaration at namespace scope if it is odr-used.
- in_class_but_out_of_source_def: external linkage. Also fine. This is actually the standard way.

In conclusion, there is (much) less undefined behaviour than you seem to think - which is good. There are however a few things, that are valid but do not really make sense like extern in unnamed namespaces.

Regarding your comment about this question: I cannot reproduce the issue and neither could other people in the comment section of that question. There are also other plausibility issues with the question you can find in its comment section. Bear in mind, that some questions on stackoverflow are asked by people who do not exactly know which steps they take when running into problems. I would not bother too much about that particular question ;)

Related Question