How to declare constexpr extern?
no you can't do it, here's what the standard says (section 7.1.5):
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template, the declaration of a function or
function template, or the declaration of a static data member of a
literal type (3.9). If any declaration of a function, function
template, or variable template has a constexpr specifier, then all its
declarations shall contain the constexpr specifier. [Note: An explicit
specialization can differ from the template declaration with respect
to the constexpr specifier. Function parameters cannot be declared
constexpr. — end note ]
some examples given by the standard:
constexpr void square(int &x); // OK: declaration
constexpr int bufsz = 1024; // OK: definition
constexpr struct pixel { // error: pixel is a type
int x;
int y;
constexpr pixel(int); // OK: declaration
};
extern constexpr int memsz; // error: not a definition
inline constexpr have external linkage?
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 inline
d) variable and you have to make sure that you don't use c
in an inline
function.
Constexpr' vs 'extern const'. Which has priority?
Using extern const
in the header file only tells the compiler that the variable exists and that it is not modifiable. It doesn't tell the compiler its value which means it's not a compile-time constant anymore. If it's not a compile-time constant then it can't be used for e.g. case
or as an array size.
As said by M.M in the comment, either use
const int MAX_NUMBER_OF_ROWS= 99;
or
constexpr int MAX_NUMBER_OF_ROWS= 99;
directly in the header file and it will be a compile-time constant in all translation units that include the header file.
How do I forward-declare a constexpr object at namespace scope?
The real answer is that gcc is plain wrong, clang is right. The code above should compile, and it will in gcc 4.9. Or so says this bug report.
constexpr variable at namespace scope with and without explicit inline definition
(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:
- internal linkage
- can appear in multiple translation units (not UB); will define different variables in different TU
- external linkage with inline specifier
- can appear in multiple translation units (not UB); will define the same variable in all TU
- 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.)
C++11, Is it possible to force an instance to be extern but also a constant expression of a non-type template parameter?
So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr [...]
Per my comment, you can. It wouldn't work for you, but it's a step that helps in coming up with something that would work:
extern constexpr int i = 10;
This is perfectly valid, gives i
external linkage, and makes i
usable in constant expressions.
But it doesn't allow multiple definitions, so it can't work in a header file which is included in multiple translation units.
Ordinarily, the way around that is with inline
:
extern inline constexpr int i = 10;
But variables cannot be declared inline
in C++11.
Except... when they don't need to be declared inline
because the effect has already been achieved implicitly:
struct S {
static constexpr int i = 10;
};
Now, S::i
has external linkage and is usable in constant expressions!
You may not even need to define your own class for this, depending on the constant's type: consider std::integral_constant
. You can write
using i = std::integral_constant<int, 10>;
and now i::value
will do exactly what you want.
Related Topics
What Do Each Memory_Order Mean
What Does Flushing the Buffer Mean
How to Append an Int to a String in C++
When Should I Use C++14 Automatic Return Type Deduction
Setupdigetdeviceproperty Usage Example
Set Precision of Std::To_String When Converting Floating Point Values
Getline Not Working Properly? What Could Be the Reasons
Run an Application in Gdb Until an Exception Occurs
How to Get Current Timestamp in Milliseconds Since 1970 Just the Way Java Gets
How Does the Range-Based for Work for Plain Arrays
C++ Correct Way to Return Pointer to Array from Function
Catching Exceptions from a Constructor's Initializer List
How to Initialise a Dynamic Array in C++
Qgraphicsview Zooming in and Out Under Mouse Position Using Mouse Wheel
Building and Accessing a List of Types at Compile Time
Stl Remove Doesn't Work as Expected
Template Within Template: Why "'>>' Should Be '> >' Within a Nested Template Argument List"