Consider code like the following, where the literal some_magic_int (e.g. 3) is given a name just to make a bit clearer what constant it represents:
void f() {
static constexpr int this_variable{some_magic_int};
do_something_with(this_variable);
}
int main() {
// ...
f();
// ...
}
I'm pretty sure constexpr has to be here: some_magic_int is literal, so it never changes, and I'm giving it a name just for clarity, not to give a mean to change it, so it should be at least const; then why not constexpr to have it at compile-time?
But what about static? Is it just unnecessary? Or is it detrimental? If so, why? And also, does it have any observable effect, when paired with constexpr in the declaration of a local variable?
As regards the question to which this is marked as duplicate of, it is about static constexpr int x [] = {}, and not static constexpr int x {}. This highlights at least one difference between that case (attributes applying to x pointer vs attributes applied to *x pointee) and my case (there's no pointer).
Furthermore, once I add constexpr to the specifier of a local variable (where it makes sense, e.g. to a int), I'm saying that variable is compile-time known. Why in the world doesn't that imply that no run-time entity is needed whatsoever?
The standard doesn’t actually ever talk about compile-time anything except to say that types are checked and templates are instantiated before execution. That means that this program must be diagnosed (not “rejected”!) even though the non-constant array length and template argument are never “used” and might plausibly be ignored by an interpreter:
template<int> void f() {}
int main(int argc,char **argv) {
if(false) {
int buf[argc]; // accepted by a common extension
f<argc>();
}
}
Beyond that, the semantics are that every evaluation is part of the ordinary execution of the program and constant folding is just an as-if optimization like any other. (After all, we can optimize argc*2*3*4 even though it contains no non-literal subexpression that could be a constant expression.) For constant expressions, this is largely unobservable because constant evaluation can’t have side effects (which also avoids interactions among constant-initialized non-block variables). It can, however, make a difference via the address of the local variable:
bool introspect(const int *p=nullptr) {
constexpr int x=0;
return p ? p==&x : introspect(&x); // always false
}
That the compiler must make such variables occupy memory if their address escapes is much of the content of the answers to the previously marked duplicate. It therefore makes sense to prefer static except perhaps when the object is large and its address doesn’t matter (e.g., for use as a template argument or via recursion).
Related
I ran across this seemingly odd behavior. A const at top level can be used for array size declarations, but not when the const is in a class.
Here's a compiler explorer demo for MSVC, CLANG and GCC all producing an error:
expression did not evaluate to a constant
It's not really a constant if it's not const at the top level?
There's some argument to be made because top level constants can often be stored in read-only memory, while constants that are not at top level cannot. But is this behavior correct?
struct A {
const int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; // C2131: expression did not evaluate to a constant
int k[ii]{};
}
Generally, you can use (meaning perform an lvalue-to-rvalue conversion on) objects with lifetime starting outside a constant expression only if they are variables marked constexpr or their subobjects (plus some other special cases, that I don't think are important here, see [expr.const]/4 for details).
That you can use a const int variable at all in a constant expression is already a very specific exception. Essentially const-qualified integral and enumeration type variables are also usable in constant expressions if you could have added constexpr to them (meaning that their initializer expression is a constant expression).
This exception is there I guess purely for historical reasons, since it had been allowed before constexpr was introduced in C++11.
Note that all of this talks about variables and their subobjects. Non-static data members are specifically not variables and the exception doesn't apply to them. With constexpr this is more obvious by not allowing it on the declaration of a non-static data member in the first place.
The historical rule was never extended to encompass other types that could be marked constexpr, so e.g. const A a; will not help although that would actually cause a to be storable in read-only memory the same way a const int would.
If an object is none of the cases mentioned above, then an lvalue-to-rvalue conversion on it in a constant expression is not allowed, since it is assumed that the value of the object is not determined at compile-time.
Now, in theory the compiler could still do some constant folding and determine that even other objects' values are definitively known at compile-time. But I think the intention is that whether or not an expression is a constant expression should be (reasonably) well-defined independently of the implementation and so shouldn't rely on how much analysis the compiler can do.
For example
A a;
A b(a);
is also guaranteed to result in b.i == 3. How far do you want to require a compiler to go back or keep track of evaluations? You would need to make some definitive specification if you want to keep the behavior consistent between compilers. But there is already a simple method to indicate that you want the compiler to keep track of the values. You just have to add constexpr:
constexpr A a;
constexpr A b(a);
Now b.i can be used as array index (whether or not it is const and whether or not it is initialized).
With the current rules, any compiler only needs to evaluate the value of objects at compile-time when it sees a constexpr variable or a const integral/enumeration type variable. For all other variables it doesn't need to keep track of values or backtrack when it sees them used in a context which requires a constant expression.
The additional effect of constexpr implying const on the variable makes sure that its value will also never be changed in a valid program and so the compiler doesn't need worry about updating or invalidating the value after the initial computation either. And whether or not an expression is a constant expression is (mostly) implementation-dependent.
ii is a compile-time constant. Its value is known at compile-time, and cannot be changed at runtime. So, ii can be used for fixed array sizes at compile-time.
A::i is not a compile-time constant. It is a non-static instance member. Its value is not known until runtime. After an A object is constructed and its i member is initialized, the value of i cannot be changed because of the const, but the caller can initialize i with whatever value it wants, eg: A a{123};, and thus different A objects can have different i values. So, i cannot be used for fixed array sizes at compile-time. But, it can be used for dynamic array sizes at runtime, via new[], std::vector, etc.
TL;DR
Your assumption that const always implies compile time constant is incorrect. See examples at the end of this answer for more details on this.
Now the problem in using a.i as the size of an array is that in standard C++, the size of an array must be a compile time constant, but since i is a non-static data member, it requires an object to be used on. In other words, after construction of the class object nonstatic data member i gets initialized, which in turn means that a.i is not a constant expression, hence we get the mentioned error saying:
expression did not evaluate to a constant
To solve this, you can make i be a constexpr static data member, as shown below. This works because using a static data member doesn't require an object instance (and hence no this pointer).
struct A {
constexpr static int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; //Correct now and works in all compilers
int k[ii]{};
}
I just don't get why a regular const works in some places but not others.
Perhaps you assuming that const implies compile time constant which is a wrong assumption. An example might help you understand this better:
int i = 10; //i is not a constant expression
const int size = i; //size is not a constant expression as the initializer is not a constant expression
//------vvvv------>error here as expected since size is not a constant expression
int arr[size]{};
On the other hand if you were to make i const as shown below, the program will work fine.
const int i = 10; //note the const added here so that now i is a constant expression
const int size = i; //size is a constant expression as the initializer is a constant expression
//------vvvv------>NO ERROR HERE as expected since size is a constant expression
int arr[size]{};
This is a follow up question to this one.
From one of the answers in the question linked, it makes sense that the purpose of declaring a variable as constexpr is not truly to inform the compiler of the possibility of using that variable as a constant expression (although this is the end behavior of the compiler) but rather to convey to other programmers the intent that the variable can be used in a constant expression. My question is whether there is any benefit, performance or otherwise, to declaring a variable as constexpr if the variable is not intended to be used in a constant expression (e.g. a constant member variable of a class which only appears in non-constant expressions with other non-const member variables). Also assume that this is not for an embedded system.
I work with code where the previous developers seem to use constexpr like it's candy even when it's not clear that the intent is for the variable to be used in a constant expression (like in the example from the previous paragraph). I want to know if they knew something that I don't.
but rather to convey to other programmers the intent that the variable can be used in a constant expression.
This is a matter of opinion but I beg to differ.
In principle, I think it is better to make everything that can be known and computed at compile time a constexpr. The fact that it can also be used in constant expressions is a side benefit. Use of constexpr may have performance related benefits too.
The key point I want to make is that "the value is known at compile time" is a characteristic of the variable/data. It is better to capture that characteristic by using a language provided feature. The only time one could justify not using it will be if there are any adverse side effects.
Yes, constexpr variables are useful for more than just conveying intent and using in other constant expressions.
If you mark a variable constexpr, the compiler will enforce that it itself is initialized with a constant expression. You can use this to make sure that the things you expect to be evaluated at compile time actually are. For example:
constexpr int constexpr_function() { return 123; }
int expensive_runtime_function() { return 123; }
void f()
{
constexpr int good1 = constexpr_function(); // OK.
// constexpr int good2 = expensive_runtime_function(); // Good: error.
const int bad1 = constexpr_function(); // OK.
const int bad2 = expensive_runtime_function(); // Bad: unexpected runtime cost.
}
I'm just wondering whether sentences like const int N=10 will be executed at compilation time. The reason I'm asking is because that the following code will work.
int main()
{
const int N=10;
int a[N]={};
return 0;
}
But this one wouldn't.
int main()
{
int N=10;
int a[N]={};
return 0;
}
The compiler must generate code "as if" the expression was evaluated at
compile time, but the const itself isn't sufficient for this. In
order to be used as the dimension of an array, for example, expression
N must be a "constant integral expression". A const int is
a constant integral expresion only if it is initialized with a constant
integral expression, and the initialization is visible to the compiler.
(Something like extern int const N;, for example, can't be used in
a constant integral expression.)
To be a constant integral expression, however, the variable must be
const; in your second example, the behavior of the compiler and the
resulting program must be "as if" the expression were only evaluated at
runtime (which means that it cannot be used as the dimension of an
array). In practice, at least with optimization, the compiler likely
would evaluate N at compile time, but it still has to pretend it
can't, and refuse to compile the code.
The compiler will probably evaluate both of the examples you provided at compile time, since even though the int N = 10; isn't const, you're not changing it anywhere and you're only assigning a constant value to it, which means the compiler can optimize this.
I recommend you take a look at the constexpr keyword introduced in C++11, which is exactly about being able to evaluate things at compile time.
Compilers will resolve const variables to literals at compile time (and also const expressions, see constant folding). The reason that the first method works is that compiler knows how much space to allocate (10*sizeof(int)) to a in the first method. In the second method the value of N is not known at compile time, and as such there is no way for the compiler to know how much space to allocate for a. Hope that helps.
This sort of thing is an implementation detail that technically is up to the compiler to choose. It could be different on different platforms.
In practice, with the most common compilers:
const int sometimes is and sometimes isn't baked at compile time. For example, the compiler clearly can't hardcode the value of a below into the object file:
int foo( int x )
{
const int a = x+ 1;
return a * 2;
}
In that function, const means it is only constant within the scope of foo(), but it is still a local stack variable.
On the other hand, const int x = 5 seems to be a literal that is usually resolved at compile time by GCC and MSVC (except sometimes they don't turn it into a literal for reasons unclear). I've seen some other compilers that won't turn it into a literal, and always put const int on the stack like an ordinary local variable.
const static int is different, because its scope is static, which means it outlives the function it is declared in, which means it will never change over the life of the program. Every compiler I've ever worked with has turned const static primitives into compile-time literals.
Objects with constructors, however, will still need to be initialized at runtime; so
class Foo {
Foo() : { CallGlobalFunction(); }
};
const static Foo g_whatever;
cannot be optimized into a literal by the compiler.
If I never use the address of a static const variable, is memory allocated for it when using a reasonably modern compiler?
It depends on the type of the variable, and on whether "constant" also means "constant expression". Example:
static const Foo = get_foo(std::cin);
static const int q = argc * 3;
static const std::string s(gets());
These variables are const, but blatantly need an actual allocation.
On the other hand, the following constant expression may never have physical storage:
static const int N = 1000;
static const std::shared_ptr<void> vp(); // constexpr constructor!
Most importantly, static constexpr member variables don't need a definition if you're careful:
struct Bar
{
int size() const { return N; }
static const int N = 8;
};
// does NOT need "const int Bar::N;"
There is chance that it isn't, but that doesn't matter. You can't rely on implementation details, only on the standard.
In practice, space for static storage can be allocated as part of the initial binary loading, or by the runtime during startup; but will always happen before user code is encountered.
In addition to the constraints that Kerrek SB mentions, the storage for a const expr value could be eliminated if the value itself is never used at runtime.
This wouldn't necessarily mean that the value needs to not be evaluated - if a static const expr were only used as a branch condition, that condition may be evaluated statically and other code paths may not be generated or may be excluded by the optimiser.
Pretty much any storage with static duration may be eliminated if the implementation can guarantee behaviour as though the storage were present - i.e. a comparison expression that can be evaluated at compile time - like a different const expr, a pointer comparison where the rhs is known to be an alias to a different variable, or perhaps an incompatible type. It may also be eliminated if the value is only read into variables that are never read themselves; or where the value may be reduced to a const expr.
struct Foo{};
static Foo bar; // static instance
Foo* func() {
if ( ! (&bar) ) { // always non-NULL
// this block may be eliminated
Foo* myCopy(new Foo(bar));
return myCopy;
}
// so 'bar' is never referred to, and we know it has no side-
// effects, so the static variable can be eliminated
return new Foo();
}
3.7.1 Static storage duration
2. If an object of static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8.
Memory for global variables is reserved by the linker, not the compiler. So the question is whether the linker is smart enough to not reserve space for global variables that are only used by value.
It depends on the type and use of such data; for example, floating point constants generally must be loaded from memory, so they must have storage even if you don't directly use the address.
Having said that, the standard does specify whether you can optimize out static storage (3.7.1.2: [basic.stc.static]):
If a variable with static storage duration has initialization or a
destructor with side effects, it shall not be eliminated even if it
appears to be unused, except that a class object or its copy/move may
be eliminated as specified in 12.8.
So if the static const variable has a constructor or destructor, it cannot be optimized out (although some compilers/linkers will do this anyway). If it doesn't, it can. Whether it will depends on the linker.
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.