Does Constexpr Imply Inline

Does constexpr imply inline?

Yes ([dcl.constexpr], §7.1.5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1.2)."

Note, however, that the inline specifier really has very little (if any) effect upon whether a compiler is likely to expand a function inline or not. It does, however, affect the one definition rule, and from that perspective, the compiler is required to follow the same rules for a constexpr function as an inline function.

I should also add that regardless of constexpr implying inline, the rules for constexpr functions in C++11 required them to be simple enough that they were often good candidates for inline expansion (the primary exception being those that are recursive). Since then, however, the rules have gotten progressively looser, so constexpr can be applied to substantially larger, more complex functions.

Are all constexpr variable implicitly inline?


Are all constexpr variable implicitly inline?

No. Only constexpr functions and constexpr static data members are implicitly inline ([dcl.constexpr]/1).

Also, how does that affect the linkage of my variable bar?

A constexpr variable is const ([dcl.constexpr]/9). A non-inline const variable that is not explicitly declared extern has internal linkage ([basic.link]/3).

Replacing constants: when to use static constexpr and inline constexpr?

In C++17, the proper way to replace those old idioms (e.g. #define) in headers in namespace scope is to use constexpr inline variables -- and not static (which is implied: they already have internal linkage).

While typically you won't encounter ODR issues (because integer compile-time constants such as those you describe are rarely ODR-used and there is a provision for their typical usage within inline functions), it is best to mark them as inline now that we have the feature in the language and avoid all problems.

See Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations? for the technical details about it.

What is the difference between inline and constexpr captureless lambda in a header?


If I understand correctly, constexpr imply inline, and lambdas are constexpr by default.

The first part is true, but not for this case. From [dcl.constexpr]/1:

A function or static data member declared with the constexpr or consteval specifier is implicitly an inline function or variable ([dcl.inline]).

In our case, we don't have either a function or a static data member, so it's not implicitly inline. You'd have to explicitly mark it as such.

The second part isn't quite right. From [expr.prim.lambda.closure]/4:

The function call operator or any given operator template specialization is a constexpr function if either the corresponding lambda-expression's parameter-declaration-clause is followed by constexpr or consteval, or it satisfies the requirements for a constexpr function ([dcl.constexpr]).

The call operator is constexpr by default, but the lambda itself is not. Which for a capture-less lambda is basically fine, you can still use the call operator - as demonstrated in the example for this section:

auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK

In short, if you're declaring this lambda in the header, you definitely need the inline keyword and it doesn't hurt to just slap on the constexpr keyword either.

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 inlined) variable and you have to make sure that you don't use c in an inline function.

inline vs. constexpr?

Asserting that something can be computed at compile-time is a pretty strong kind of optimization.

Inlining merely removes a function call, by copy/pasting the function body into the call site. The function body still has to be executed, you just save the overhead of a function call.

But if you make the same code be evaluated at compile-time, it is free at runtime.

But neither inline nor constexpr are primarily about optimization. inline's main purpose is to suppress the one-definition-rule, so that functions can be defined in headers (which is useful for templates, and incidentally, also makes the inlining optimization easier)

And constexpr is there because it is useful in metaprogramming, and incidentally, it may help the compiler better optimize the code, by moving more computations to compile-time.

What's the difference between static constexpr and static inline variables in C++17?

You don't have to specify an initializer for mySecondVar at the point of declaration. Nor is the initializer required to be constexpr itself.

This means that if we attempt to define myFirstVar like this:

class MyClass {
static constexpr int myFirstVar;
};

int MyClass::myFirstVar = 1;

Or like this:

#include <cstdlib>

class MyClass {
static constexpr int myFirstVar = rand();
};

It's ill-formed either way. constexpr semantics demand it and for a good reason.

The inline specifier approach allows us to include a static variable definition in the header itself, without the initializer being constexpr; or if the initializer is fairly complex it doesn't have to be in the class definition itself.

So this is a perfectly valid header in C++17:

#include <cstdlib>

class MyClass {
static const int mySecondVar;
};

inline const int MyClass::mySecondVar = rand();

The standard promises us that all translation units that include the header will see the same value for the variable, even though we won't know what it is until run-time.

It's mostly a library writers tool. Assume your library is header only. Then in the olden days, what were your options if you needed a static constant defined like this?

Well, you could have an object file shipped with your library. It will be compiled from a translation unit that contains just the constant definition. Now the library isn't header-only.

Or you could rely on inline functions instead. The inline variable effect can be achieved with the following:

class MyClass {
static inline int mySecondVar();
};

inline int MyClass::mySecondVar() {
static const int value = rand();
return value;
}

But it's hidden behind a wall of syntax, and masks what is essentially a constant, with a function call operator.



Related Topics



Leave a reply



Submit