If I define a function in my program.cpp:
constexpr bool isThree(const int number)
{
return number == 3;
}
is that any different from declaring it static?
static constexpr bool isThree(const int number)
{
return number == 3;
}
It seems that those should be equivalent, since constexpr means the function is inline and therefore not shared among compilation units.
Are constexpr global functions implicitly static?
constexpr functions are implicitly inline.
inline is a linking feature. An inline function with definitions in different compilation units is not an error; if their definitions vary, your program is ill-formed no diagnostic required, but if they have the same definition then all but one version is discarded and that version is used.
static, on a non-method function, is also a linking feature. A static definition is not shared outside of its compilation unit; the compilation unit does not 'advertise' that it has a definition for isThree.
static on a method function has nothing to do with linking. In that case, it just means that this is not implicitly passed to the function. A method with/without this it doesn't work has differences, but they are mostly unrelated to them being constexpr. Note that in at least c++14 a constexpr method that doesn't use this can still be constant evaluated. Some versions of c++ make constexpr methods implicitly const; c++17 does not.
&isThree in one compilation unit and &isThree in another can (and usually do) vary when static (barring aggressive ICF, which is a matter for a different question). When inline they may not vary.
inline functions are shared between compilation units. Their full definition is also often visible in all compilation units aware of it, so it makes compiler "inlining" (as opposed to the keyword) your code easier. static are not. constexpr functions are implicitly inline, but not implicitly static.
Note that constexpr functions can be evaluated in a runtime context sometimes. When evaluated in a compile time context, their inline vs static or linkage state really doesn't matter.
constexpr means other things as well, but you wanted to know the difference between two different constexpr declarations, and none of those meanings change.
constexpr functions are not implicitly static. They have the same linkage as non-constexpr functions:
// external linkage
constexpr int f1(int x) { /* ... */ }
// internal linkage
static constexpr int f2(int x) { /* ... */ }
// internal linkage
namespace {
constexpr int f3(int x) { /* ... */ }
}
// no linkage
void enclosing() {
struct S {
constexpr int f4(int x) { /* ... */ }
};
}
When a constexpr function has external linkage, it has the same address in all translation units. When it has internal linkage, there is a different copy in each translation unit, and those copies have different addresses. However, I believe the result of calling a constexpr function should not depend on whether it has internal or external linkage (since constexpr functions may not contain static variables).
Related
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 (
Consider the following header and assume it is used in several TUs:
static int x = 0;
struct A {
A() {
++x;
printf("%d\n", x);
}
};
As this question explains, this is an ODR violation and, therefore, UB.
Now, there is no ODR violation if our inline function refers to a non-volatile const object and we do not odr-use it within that function (plus the other provisions), so this still works fine in a header:
constexpr int x = 1;
struct A {
A() {
printf("%d\n", x);
}
};
But if we do happen to odr-use it, we are back at square one with UB:
constexpr int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
Thus, given we have now inline variables, should not the guideline be to mark all namespace-scoped variables as inline in headers to avoid all problems?
constexpr inline int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
This also seems easier to teach, because we can simply say "inline-everything in headers" (i.e. both function and variable definitions), as well as "never static in headers".
Is this reasoning correct? If yes, are there any disadvantages whatsoever of always marking const and constexpr variables in headers as inline?
As you have pointed out, examples one and third does indeed violate ODR as per [basic.def.odr]/12.2.1
[..] in each definition of D, corresponding names, looked up according to [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization, except that a name can refer to
a non-volatile const object with internal or no linkage if the object
is not odr-used in any definition of D, [..]
Is this reasoning correct?
Yes, inline variables with external linkage are guaranteed to refer to the same entity even when they are odr-used as long all the definitions are the same:
[dcl.inline]/6
An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case ([basic.def.odr]). [..] An inline function or variable with external linkage shall have the same address in all translation units.
The last example is OK because it meets and don't violate the bold part of the above.
are there any disadvantages whatsoever of always marking const and constexpr variables in headers as inline?
I can't think of any, because if we keep the promise of having the exact same definition of an inline variable with external linkage through TU's, the compiler is free to pick any of them to refer to the variable, this will be the same, technically, as having just one TU and have a global variable declared in the header with appropriate header guards
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.
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
This is my knowledge about function declaration and definition. If there is anything wrong, please correct me.
// Function Declaration
// This is usually put in .h header file
int occur (const char* sentence, const char& achar);
// Function Definition
// This is usually put in .cpp
int occur (const char* sentence, const char& achar) { // do job and return }
I am reading the "C++ Primer 5th Edition". Under "inline and constexpr functions # Chapter 6.5.2 P.240", it says
Unlike other functions, inline and constexpr functions may be defined
multiple times in the program.
I come up with something like this in my head:
// function delcaration .h file
constexpr int returnfour();
// function definition in .cpp file
constexpr int returnfour () { return 4; }
constexpr int returnfour () { return 4; }
Is it correct to have multiple definitions like this? What does defined multiple times in the program mean and when does someone want to do it?
Unlike other functions, inline and constexpr functions may be defined multiple times in the program.
Say you have a.h:
inline int foo() { return 10; }
constexpr int bar() { return 20; }
Now, you #include the file in couple of .cpp files.
file1.cpp:
#include "a.h"
// ... other functions
file2.cpp:
#include "a.h"
// ... other functions
int main() { return 0; }
When you compile those files, the functions foo and bar are defined in the object code of file1.cpp as well as the object code of file2.cpp. When you link those object code to create an executable, there are two definitions each of foo and bar. This is legal.
However, you are not allowed to have multiple definitions of the same inline function or constexpr function in the same compilation unit.
Using:
inline int foo() { return 10; }
inline int foo() { return 10; }
or
constexpr int bar() { return 20; }
constexpr int bar() { return 20; }
in a single cpp file is not legal.
A function declaration provides information to the compiler about the function's name, the number and type of arguments it accepts, and its return value. The compiler uses this information to check statements that attempt to call the function.
A function definition is a specific type of declaration that also includes a compound statement that implements the function (the part between the { and } of the function body).
The statement about inline and constexpr functions having more than one definition does not mean that the definition can be repeated multiple times in a single compilation unit. C++ has a separate compilation model, so the compiler does not have visibility of function definitions in one compilation unit when compiling another. However, multiple compilation units can each define an inline or constexpr function (e.g. by each #includeing the same header). The results - for the program as a whole - are undefined if different compilation units have non-equivalent definitions of the same function. A result of this is that the code for constexpr and inline functions may be duplicated within the program (e.g. inlined in multiple places, not inlined but implemented locally within an object file in a manner that is not visible to other compilation units, etc) and it is up to the compiler (usually working with other parts of the build chain) to ensure this happens in a consistent manner across compilation units.
As mentioned above inline and constexpr functions can be defined multiple times. But they should be only defined only once in each compilation units. By extension if you define them in the header and include the header in multiple compilation units they can be only defined once in the header file. NOTE: They should also have the same signature otherwise the behavior is undefined.
Both inline functions and constexpr functions are resolved at compile time and that is the reason it is possible to have multiple definitions across compilation units as long as you don't violate the ODR(one definition rule) within the compilation unit.
Please see the relevant excerpts from the C++ standard document:
7.1.5 The constexpr specifier
constexpr functions and constexpr constructors are implicitly
inline functions (7.1.2).
3.2 One-definition rule
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found
in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.