inline constexpr have external linkage? [duplicate] - c++

This question already has answers here:
constexpr variable at namespace scope with and without explicit inline definition
(2 answers)
Closed 7 months ago.
I know global constexpr variables have internal linkage. so how is it that inline constexpr are introduced with having external linkage? does adding inline just converts internal linakges to external linkages in all cases?

There seems to be a little bit of confusion about what "linkage" and "inline" actually means. They are independent (orthogonal) properties of a variable, but nevertheless coupled together.
To inline a variable one declares it inline. Declaring a constexpr variable at namescope does not imply inline [1]. To declare a variable to have internal linkage one declares it static or more preferrable puts it into an anonymous namespace [2],[3]. For const and constexpr (which implies const) variables there is a special rule, which gives them internal linkage as long as they are non-inline [4].
Because constexpr variables require an immediate definition [5], you typically want them to be be inline which allows multiple (equivalent) definitions in multiple translation units:
\\ c.hpp
inline constexpr int c = 0; // define it in header
\\ a.cpp
#include "c.hpp" // c is defined in a.cpp
int a = c; // use it
\\ b.cpp
#include "c.hpp" // c is re-defined in b.cpp
int b = c; // use it
The linkage of c in that example above is external, because the special rule for const variables only applies to non-inline variables.
Note that when ommiting the inline specifier in the example makes each source file get an independent non-inline definition of c with internal linkage. It will still compile but you have to be careful to not use c in any inline functions [6].
You can put inline constexpr variables into an anonymous namespace or declare it static to make its linkage internal. If we changed the example above into
\\ c.hpp
namespace {
inline constexpr int c = 0;
};
\\ a.cpp
...
the effects would be almost the same as if ommitin the inline in the original example. Each translation unit gets its own version of the (now inlined) variable and you have to make sure that you don't use c in an inline function.

inline variable or function make compiler merge* multiple definition into one.
for the same reason, multiple inline constexpr with same name would has only one instance after link.
then you're accessing the variable in other TU, it's effectively has external linkage.
* it's undefined behavior if the definition are not the same though.
** you cannot declare extern constexpr, btw

I know global constexpr variables have internal linkage
You are missing a few qualifiers (emphasis mine):
internal linkage
Any of the following names declared at namespace scope have internal
linkage:
...
non-volatile non-template (since C++14) non-inline (since C++17) non-exported (since C++20) const-qualified variables (including
constexpr) (since C++11) that aren't declared extern and aren't
previously declared to have external linkage;
...

Related

Why is constexpr solving duplicated definition?

I have a header file where string are defined as static global.
namespace space {
#define NAME(P) static std::string const s_##P = #P
NAME(foo); NAME(bar); //... other values
#undef NAME
}
In another header, an enum is defined and a template specialization provides the mapping between the enum and a string in space.
enum class letter { alpha, beta };
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> std::string const & mapping<letter::P1>() { return space::s_##P2; }
MAPPING(alpha,foo)
MAPPING(beta,bar)
#undef MAPPING
The above code doesn't link when the header is included in more than one translation unit because the specializations definitions do not match - due to global redefinition per translation unit (I guess).
Wrapping the mapping functions in anonymous namespace or adding static keyword solves the linking issue but then the compiler complains that the functions are defined but not used [-Wunused-function].
template<letter> static std::string const & mapping();
But, defining the specializations as constexpr, there is no longer any link or warning issue.
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> constexpr std::string const & mapping<letter::P1>() { return space::s_##P2; }
I understand why the non-static version fails at link time and why the static version works and triggers warnings. But I don't understand why the constexpr specifier solves both issues.
Can you please give an explanation and even better, a rational in the standard ?
Function template specializations are functions, and are therefore subject to the one-definition rule in the same manner as functions that are not template specializations.
The linker errors you saw when the functions were declared neither static nor constexpr were due to multiple definitions of the same function template specializations which each had external linkage.
When you added static, you made the linkage internal. This made it safe for each translation unit to contain its own copy of the definitions. However, in any TU in which those functions were not called, the compiler knew that (due to internal linkage) they could not be called from any other TU either, making them unused.
With constexpr, the functions become inline implicitly according to the standard, but their linkage is not affected. Since they are inline, you can have multiple definitions, but since they have external linkage, the compiler does not complain when one TU does not use them.
functions declared with the constexpr specifier are inline functions.
From the C++ 20 Standard (9.2.5 The constexpr and consteval specifiers)
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template or the declaration of a function or
function template. The consteval specifier shall be applied only to
the declaration of a function or function template. A function or
static data member declared with the constexpr or consteval specifier
is implicitly an inline function or variable (

Why are non member static constexpr variables not implicitly inline?

In C++17 we got inline variables and I have assumed that global constexpr variables are implicitly inline.
But apparently this is true only for static member variables.
What is the logic/technical limitation behind this?
source:
A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.
The reason why constexpr static data members were made implicitly inline was to solve a common problem in C++: when defining a class-scoped constant, one was previously forced to emit the definition in exactly one translation unit, lest the variable be ODR-used:
// foo.h
struct foo {
static constexpr int kAnswer = 42;
};
// foo.cpp
// a linker error will occur if this definition is omitted before C++17
#include "foo.h"
constexpr int foo::kAnswer;
// main.cpp
#include "foo.h"
#include <vector>
int main() {
std::vector<int> bar;
bar.push_back(foo::kAnswer); // ODR-use of 42
}
In such cases, we usually care only about the value of the constant, not its address; and it's convenient for the compiler to synthesize a unique location for the constant in case it really is ODR-used, but we don't care where that location is.
Thus, C++17 changed the rules so that the out-of-line definition is no longer required. In order to do so, it makes the declaration of foo::kAnswer an inline definition, so that it can appear in multiple translation units without clashing, just like inline functions.
For namespace-scope constexpr variables (which are implicitly static, and therefore have internal linkage, unless declared extern) there is no similar issue. Each translation unit has its own copy. inline, as it's currently specified, would have no effect on such variables. And changing the existing behaviour would break existing programs.
The point here is that constexpr int x = 1; at namespace scope has internal linkage in C++14.
If you make it implicitly inline without changing the internal linkage part, the change would have no effect, because the internal linkage means that it can't be defined in other translation units anyway. And it harms teachability, because we want things like inline constexpr int x = 1; to get external linkage by default (the whole point of inline, after all, is to permit the same variable to be defined in multiple translation units).
If you make it implicitly inline with external linkage, then you break existing code:
// TU1
constexpr int x = 1;
// TU2
constexpr int x = 2;
This perfectly valid C++14 would become an ODR violation.

Why does cppreference define type_traits xxx_v shortcuts as inline constexpr and not just constexpr?

Why does cppreference define type_traits xxx_v shortcuts as inline constexpr and not just constexpr?
For example, see is_integral_v:
template< class T >
inline constexpr bool is_integral_v = is_integral<T>::value;
Is this just a matter of style or is there some difference in behavior? As far as I know constexpr variables are implicitly inline.
Edit: Looking at the draft of the latest standard, it also uses inline constexpr. The question actually applies to the standard, then.
[dcl.constexpr]/9
A constexpr specifier used in an object declaration declares the object as const.
[basic.link]/3.2
A name having namespace scope has internal linkage if it is the name of
-a non-inline variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage
Without inline specifier, is_integral_v would have internal linkage. This could be problematic if you compared two pointers to this same variable name taken in different translation unit.
Nota Bene: the inline specifier is redundant with constexpr only if the variable is a class static data member.
Following an exemple of easy violation of the one definition rule that could happen if is_integral_v where not inline.
bad_type_trait.h
template<class T>
constexpr auto bad_is_integral_v=std::is_integral<T>::value;
my_header.h
#include "bad_type_trait.h"
void f(const bool& x);
inline void g()
{
f(bad_is_integral_v<int>);
//g ODR use the static variable bad_is_integral_v.
//"ODR use" approximate definition is:
// the variable is refered by its memory address.
}
source1.cpp
#include "my_header.h"
void my_func1(){
g(); //the definition of g in this translation unit.
}
source2.cpp
#include "my_header.h"
void my_func2(){
g(); //is not the same as the definition of g in this translation unit.
}
In the two translation units, the variable bad_is_integral_v is instantiated as separate static variables. The inline function g() is defined in these two translation units. Inside the definition of g(), the variable bad_is_integral_v is ODR used, so the two definitions of g() are different, which is a violation of the one definition rule.
[basic.link]/3.2 applies to names of "a non-inline variable of non-volatile const-qualified type". A variable template isn't a variable, just like a class template isn't a class, a function template isn't a function, and a cookie cutter isn't a cookie. So that rule doesn't apply to the variable template is_integral_v itself.
A variable template specialization is a variable, however, so there are some questions about whether that rule gives it internal linkage. This is core issue 1713, the direction of which is that the rule is not applicable.
Core issue 1713, however, wasn't resolved in time for C++17. So LWG decided to simply plaster inline all over the variable templates just to be safe, because they don't hurt, either.

Difference between constexpr and static constexpr global variable

In the C++11 standard, what is the difference between constexpr and static constexpr global variables when defined in a header? More specifically, when multiple translation units include the same header, which declaration (if any) is guaranteed to define the same variable across the translation units?
e.g.,
cexpr.h:
#ifndef CEXPR_H
#define CEXPR_H
constexpr int cint = 1;
static constexpr int scint = 1;
#endif
a.cpp:
#include "cexpr.h"
b.cpp:
#include "cexpr.h"
In your current example there is no difference: On variable declarations, constexpr implies const, and a const variable at namespace scope has internal linkage by default (so adding static does not change anything).
In C++14, you cannot declare a variable as constexpr and have it have external linkage unless you only ever do this in one single translation unit. The reason is that constexpr variables require an initializer, and a declaration with initializer is a definition, and you must only have a single definition.
However, what you can do is use a normal integral constant, which you can declare (not define) as extern, and in the translation unit where it is defined it can even be used as a constant expression:
lib.h:
extern const int a;
lib.cpp:
#include "lib.h"
const int a = 10;
int b[a] = {1, 2, 3}; // OK in this translation unit
In C++17, there is a new feature "inline variables" which lets you say:
inline constexpr int a = 10;
And this is an "inline definition" that can appear repeatedly, and each definition defines the same entity (just like all the other "inline" entities in the language).
I think this article explains more clear. 6.8 — Global constants and inline variables
Because const globals have internal linkage, each .cpp file gets an independent version of the global variable that the linker can’t see. In most cases, because these are const, the compiler will simply optimize the variables away.
The term “optimizing away” refers to any process where the compiler optimizes the performance of your program by removing things in a way that doesn’t affect the output of your program. For example, lets say you have some const variable x that’s initialized to value 4. Wherever your code references variable x, the compiler can just replace x with 4 (since x is const, we know it won’t ever change to a different value) and avoid having to create and initialize a variable altogether.
So, the "cint " and "scint" are all internal linkage variables.
The best practice to define global variable after C++ 17:
inline constexpr double pi = 0;
Working Mechanism:
C++17 introduced a new concept called inline variables. In C++, the term inline has evolved to mean “multiple definitions are allowed”. Thus, an inline variable is one that is allowed to be defined in multiple files without violating the one definition rule. Inline global variables have external linkage by default.
Inline variables have two primary restrictions that must be obeyed:
1) All definitions of the inline variable must be identical (otherwise, undefined behavior will result).
2) The inline variable definition (not a forward declaration) must be present in any file that uses the variable.
The compiler will consolidate all inline definitions into a single variable definition. This allows us to define variables in a header file and have them treated as if there was only one definition in a .cpp file somewhere. These variables also retain their constexpr-ness in all files in which they are included.
If you can, prefer the static constexpr because with the constexpr it depends on the toolchain how likely it will get done on compile-time. Gcc is most aggressive, MSVS least aggressive and clang is in between.
Instead of leaving some values up to optimizer to decide it will do it at compile-time be more explicit and force it.
Reference:
https://www.youtube.com/watch?v=4pKtPWcl1Go

When sharing a const across files using extern, why is extern needed on the definition?

Page 60 of C++ Primer 5th edition talks about sharing const variables across files like so
//file_1.cc
extern const int bufSize = fcn();
//file_1.h
extern const int bufSize;
When would bufSize be defined and what is the purpose of extern on file_1.cc? I understand that file_1.cc would define it, but Page 45 of the same book says that providing an initializer for a variable overrides the extern, so why is it necessary to have extern on the const's definition?
According to the standard,
A name having namespace scope (3.3.6) has internal linkage if it is the name of ... a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared
extern nor previously declared to have external linkage
So there is a special rule that variables at namespace scope have internal linkage when const or constexpr even if they would otherwise have external linkage. I'm not entirely sure why this rule exists but I suspect it's to allow the compiler to inline const variables and hence not allocate any storage for them at all. The extern specifier explicitly overrides this and makes the variable have external linkage again.
providing an initializer for a variable overrides the extern
Now this is a bit different. By default a declaration of a variable is also a definition, but extern suppresses this so you can declare a variable without defining it (i.e. because its definition is in another translation unit). But if you have an initializer then it overrides the extern and the declaration once again becomes a definition. This isn't really related to the rules about internal and external linkage above.