简体   繁体   中英

constexpr variable at namespace scope without explicit inline definition and with

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

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 (eg 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 - eg 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;)

(Since the question is tagged C++17, I'll use the draft standard N4659 as the reference, which avoids complication due to modules.)

First, be aware that names in different translation units refer to the same entity only if they have external linkage ( [basic.link]/9 ). Names with internal linkage always refer to different entities in different translation units, even if their definitions appear the same.

Therefore, we can put these definitions into three groups:

  1. internal linkage
    • can appear in multiple translation units (not UB); will define different variables in different TU
  2. external linkage with inline specifier
    • can appear in multiple translation units (not UB); will define the same variable in all TU
  3. external linkage without inline specifier
    • cannot appear in multiple translation units (UB: ODR violation)

(Definitions in the first group can be problematic if the variable is odr-used in another definition with external linkage, which might violate [basic.def.odr]/(6.2) .)

The following definitions belong to the first group (internal linkage):

  • both of global_non_expl_inline (It's a non-inline variable of non-volatile const-qualified type, and has no previous declaration. Thus it matches [basic.link]/(3.2) )
  • both of global_non_expl_inline_static ( [basic.link]/(3.1) )
  • both of global_expl_inline_explicit_static ( [basic.link]/(3.1) )
  • global_expl_inline_explicit_extern_but_unnamed_ns ( [basic.link]/(4.1) )

The following definitions belong to the second group (external linkage with inline specifier):

  • both of global_expl_inline
  • both of global_expl_inline_explicit_extern

The following definition belongs to the third group (external linkage without inline specifier):

  • bar::in_class_but_out_of_source_def

( bar::in_class_static is not defined, it can appear in multiple TU but can't be odr-used without a definition.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM