Constant initialization in a dynamic way - c++

I think that the the variable declared as const applies only Static Initialization. I've written the following:
#include <cstdlib>
#include <iostream>
struct A{ };
const A *i = new A();
int main(){ }
and it works fine.
Ideone
But I expected that the the code is invalid because new A() is a new-expression and it is not a constant expression. Actually:
sec. 5.19/2 N3797:
A conditional-expression e is a core constant expression unless the
evaluation of e, following the rules of the abstract machine (1.9),
would evaluate one of the following expressions:
[...]
— a new-expression (5.3.4);
[...]
and
A constant expression is either a glvalue core constant expression
whose value refers to an object with static storage duration or to a
function,

First off, you probably meant A * const i (a constant pointer to A) and not const A * i (a non-constant pointer to const A).
Still, even with this modification, it is perfectly legal to initialise a const variable with a value that is not a constant expression (such as a value computed at runtime). However, it is then not possible to use such a variable inside constant expressions. If you tried that, the constant expression definition would kick in and you'd get an error.

The initialisation of a const variable does not require a constant expression.

Related

How to make `this` pointer constant expression?

This is a follow-up question is my previous question: Why are member functions returning non-static data members not core constant expressions?
The reduced version of the example mentioned in that question is:
struct S {
const bool x = true;
constexpr bool f() { return x; }
};
int main() {
S s{};
static_assert(s.f()); // error: 's' is not a constexpr;
}
The applicable wording from the standard is N4861: [expr.const]/(5.1):
An expression E is a core constant expression unless the evaluation
of E, following the rules of the abstract machine
([intro.execution]), would evaluate one of the following:
(5.1) this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of E;
As far as I can parse, the expression E is s.f() and it evaluates this since s.f() returns a non-static member this->x. But that falls under the "except" part: the member function s.S::f() is constexpr function that's being evaluated as part of s.f(). If I parsed correctly, I'm expecting s.f() to be constant expression and the assertion success.
However, this bullet doesn't specify a requirement that says that s has to be a constant expression. I can't understand why declaring s as constexpr compiles the program even though there's no requirement, defined in this bullet, for s to be constexpr.
I'm just applying the wording (5.1) in my example but I can't see that constexpr is required here unless I'm missing any other rule.
Because return x; performs lvalue-to-rvalue conversion, the whole kaboodle is not a core constant expression:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
an lvalue-to-rvalue conversion unless it is applied to
a non-volatile glvalue that refers to an object that is usable in constant expressions, or
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of E;
lvalue-to-rvalue conversion is applied to this->S::x, which is generally forbidden, and neither of the exceptions apply to permit it.
The more relevant exception applies if x (which resolves to this->S::x) is an object that is usable in constant expressions. But it only would be if the struct S object were usable in constant expressions:
a non-mutable subobject or reference member of any of the above.
That requires it to be potentially-constant:
A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.
A constant-initialized potentially-constant variable is usable in constant expressions at a point P if ...
And S s{}; is not potentially-constant. So it is not usable in constant expressions, and neither are its subobjects.
To answer the title question, this is not a core constant expression, because it is the address of an object with automatic storage duration; that address may change at runtime. This is completely irrelevant for the static_assert in the question code: Being a constant pointer value is neither necessary nor sufficient for a this pointer to be "usable in constant expressions", which in turn is not sufficient for the object found through the pointer to be usable in constant expressions.

Why this expression is not constant expression [duplicate]

This is a follow-up question is my previous question: Why are member functions returning non-static data members not core constant expressions?
The reduced version of the example mentioned in that question is:
struct S {
const bool x = true;
constexpr bool f() { return x; }
};
int main() {
S s{};
static_assert(s.f()); // error: 's' is not a constexpr;
}
The applicable wording from the standard is N4861: [expr.const]/(5.1):
An expression E is a core constant expression unless the evaluation
of E, following the rules of the abstract machine
([intro.execution]), would evaluate one of the following:
(5.1) this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of E;
As far as I can parse, the expression E is s.f() and it evaluates this since s.f() returns a non-static member this->x. But that falls under the "except" part: the member function s.S::f() is constexpr function that's being evaluated as part of s.f(). If I parsed correctly, I'm expecting s.f() to be constant expression and the assertion success.
However, this bullet doesn't specify a requirement that says that s has to be a constant expression. I can't understand why declaring s as constexpr compiles the program even though there's no requirement, defined in this bullet, for s to be constexpr.
I'm just applying the wording (5.1) in my example but I can't see that constexpr is required here unless I'm missing any other rule.
Because return x; performs lvalue-to-rvalue conversion, the whole kaboodle is not a core constant expression:
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
an lvalue-to-rvalue conversion unless it is applied to
a non-volatile glvalue that refers to an object that is usable in constant expressions, or
a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of E;
lvalue-to-rvalue conversion is applied to this->S::x, which is generally forbidden, and neither of the exceptions apply to permit it.
The more relevant exception applies if x (which resolves to this->S::x) is an object that is usable in constant expressions. But it only would be if the struct S object were usable in constant expressions:
a non-mutable subobject or reference member of any of the above.
That requires it to be potentially-constant:
A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.
A constant-initialized potentially-constant variable is usable in constant expressions at a point P if ...
And S s{}; is not potentially-constant. So it is not usable in constant expressions, and neither are its subobjects.
To answer the title question, this is not a core constant expression, because it is the address of an object with automatic storage duration; that address may change at runtime. This is completely irrelevant for the static_assert in the question code: Being a constant pointer value is neither necessary nor sufficient for a this pointer to be "usable in constant expressions", which in turn is not sufficient for the object found through the pointer to be usable in constant expressions.

The question about a glvalue constant expression used in a context that requires a constant expression

#include <iostream>
constexpr int func2(int const& id){
return id;
}
template<int v>
struct Test{
};
int main(){
const int v = 0;
Test<func2(v)> c;
}
Consider the above code,I just don't understand why the code is well-formed.My pointview is that the name v is used as a glvalue when evalute expression func2,becuase the parameter of func2 is of reference type,the v need to be bound to the id-expression id.So we look at the requirement of a glvalue constant expression,here are quotes about that.
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints.
We ignore the case of prvalue,because here v is used as a glvalue.
An entity is a permitted result of a constant expression is:
An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.
In my program portion,The const int v = 0; does not have static storage duration,it just has automatic storage duration.So when evaluting the expression func2(v) to determine whether it is a constant expression,Firstly,the v must be a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression,therefore,why the program is well-formed here?If I lose any important quote,Please correct me.
We ignore the case of prvalue, because here v is used as a glvalue
Is it though? This is an example from cppreference:
void test() {
static const int a = std::random_device{}();
constexpr const int& ra = a; // OK: a is a glvalue constant expression
constexpr int ia = a; // Error: a is not a prvalue constant expression
const int b = 42;
constexpr const int& rb = b; // Error: b is not a glvalue constant expression
constexpr int ib = b; // OK: b is a prvalue constant expression
}
And yes, const int b = 42 is rather weird here because technically speaking, you can bind b to const int&, const_cast the const away and assign a runtime value to it. However, considering what is an integral constant expression and what are the requirements of a const object it makes perfect sense:
Integral constant expression is an expression of integral or unscoped
enumeration type implicitly converted to a prvalue, where the
converted expression is a core constant expression. If an expression
of class type is used where an integral constant expression is
expected, the expression is contextually implicitly converted to an
integral or unscoped enumeration type.
Variable b sure does look like something you could implicitly convert to a prvalue constant expression because it basically serves as an alias for literal 42 in this context and integer literals are prvalues by definition.
Now for the problematic part - this:
const object - an object whose type is const-qualified, or a
non-mutable subobject of a const object. Such object cannot be
modified: attempt to do so directly is a compile-time error, and
attempt to do so indirectly (e.g., by modifying the const object
through a reference or pointer to non-const type) results in undefined
behavior.
And:
A core constant expression is any expression whose evaluation would
not evaluate any one of the following:
...
an expression whose evaluation leads to any form of core language
undefined behavior (including signed integer overflow, division by
zero, pointer arithmetic outside array bounds, etc). Whether standard
library undefined behavior is detected is unspecified.
Means that as soon as you start doing funny things with that b, you can expect anything to happen. For example, this is what I tried doing to your code in latest MSVC with all standard-conformance options switched on:
#include <iostream>
#include <random>
constexpr int func2(int const& id) {
return id;
}
template<int v>
struct Test {
long array[v];
};
int main() {
const int v = 0;
const int& ref = v;
const_cast<int&>(ref) = std::random_device()() % std::numeric_limits<int>::max();
Test<func2(v)> c;
return 0;
}
With language extensions turned on I got a C4200: nonstandard extension used : zero-sized array in struct/union warning. After switching them off, the program wouldn't compile. And when I deleted the array part from the struct it started compiling again.
I try to answer this question.why the func2(v) is a constant expression,Becuase For expression func2(v),when evaluting this postfix-expression,there's no requirement that v must be a glvalue constant expression in the list of "would evaluate one of the following expressions:",Even,these rules does not mandate that the one expression within a potentially core constant expression would be a glvalue constant expression,only require the expression does not violate the listed requirement.So let's continue,When initialization of the parameter,It's another rule here:
A full-expression is:
[...]
an init-declarator or a mem-initializer, including the constituent expressions of the initializer
So,when evalute this full-expression,it only does not violate these listed condition,then the func2(v) would be evaluted as a constant expression,So let's look at these rules:
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
it is initialized with a constant expression or,
its lifetime began within the evaluation of e;
For id-expression id,its preceding initialization is the corresponding argument,Because of this rule:
When a function is called, each parameter ([dcl.fct]) shall be initialized ([dcl.init], [class.copy], [class.ctor]) with its corresponding argument.
So,the first condition is true.And "it is initialized with a constant expression" is false,the condition "its lifetime began within the evaluation of e" is true.In conlusion,the expression func2(v) indeed a constant expression

Constexpr Class taking const references not compiling

I have the following sample code
template<class T1, class T2>
class Operation
{
public:
constexpr Operation(const T1& lhs, const T2& rhs) noexcept
: m_lhs(lhs), m_rhs(rhs) { }
private:
const T1& m_lhs;
const T2& m_rhs;
};
int main()
{
constexpr int a = 3;
constexpr int b = 4;
constexpr Operation op(a, b);
return 0;
}
Compiling this with cygwin (gcc 8.2) I get
error: 'Operation<int, int>{a, b}' is not a constant expression:
constexpr Operation op(a, b);
With MSVC 2019 it compiles fine, but IntelliSense ironically underlines the a in op(a, b) with the tooltip "expression must have a constant value".
Any advice as to what the issue is, and how to fix it?
Yeah, this rule is one of the more complex ones as far as constant evaluation is concerned.
Basically, you cannot have a constexpr reference to an object that doesn't have static storage duration. Taking a reference to an object is basically copying its address - and in order for an object's address to be a constant expression, the address itself needs to be constant - so it has to persist. That is, it needs to be static.
So if you change the things you're referring to to have static storage duration instead, everything works:
static constexpr int a = 3;
static constexpr int b = 4;
constexpr Operation op(a, b); // now ok
The specific rule your program violates is [expr.const]/10, and T.C. helped me understand how it applies. Declaring a constexpr variable requires the initialization to be a constant expression ([dcl.constexpr/10]):
In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression.
We don't say this, but it makes sense and certainly helps resolve this particular situation, but the "full-expression of the initialization" can be interpreted as a prvalue -- since a prvalue is an expression whose evaluation initializes an object ([basic.lval]/1).
Now, [expr.const]/10 reads:
A constant expression is either a glvalue core constant expression [...], or or a prvalue core constant expression whose value satisfies the following constraints:
if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,
[...],
if the value is an object of class or array type, each subobject satisfies these constraints for the value.
An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.
The initialization Operation(a, b) is a prvalue, so we need each reference data member to refer to an entity that is permitted as a result of a constant expression. Our reference data members refer to a and b, neither of which has static storage duration nor are temporaries nor are non-immediate functions. Hence, the overall initialization isn't a constant expression, and is ill-formed.
Making a and b static gives them static storage duration, which makes them permitted results of constant expressions, which makes the prvalue initialization satisfy all the requirements, which makes the declaration of op valid.
This is all a long winded way of saying: when dealing with constant evaluation, everything everywhere has to be constant all the way down. Some of our ways of wording this are very complex (like this one), but it's based on the fundamental idea that the model of constant evaluation is basically like pausing evaluating the code to go run a separate program to produce an answer. Producing op requires these addresses to be known, fixed things - and that only happens for static storage duration.

Why references can't be used with compile time functions?

I have two snippets.
The first snippet:
#include <string>
template <typename T>
constexpr bool foo(T&&) {
return false;
}
int main() {
std::string a;
if constexpr (foo(a)) {
}
}
The second snippet:
#include <string>
template <typename T>
constexpr bool foo(T&&) {
return false;
}
int main() {
std::string a;
std::string& x = a;
if constexpr (foo(x)) {
}
}
The first one compiles, but the second one does not compile (error message: error: the value of ‘x’ is not usable in a constant expression. Why? Why a is usable in a constant expression and x is not?
The command, used to compile g++ -std=c++17 main.cpp.
Because usually a constant expression cannot evaluate a reference that refers to an object with automatic storage duration. Here I mean "evaluate" by determining the identity of the object, not by determining the value of the object. So even the value of the object a is not required in your example (i.e. no lvalue-to-rvalue conversion is applied), foo(x) is still not a constant expression.
Note foo(a) does not evaluate any reference. Although the parameter of foo is a reference, it is not evaluated as an expression. In fact, even if it was evaluated, for example,
template <typename T>
constexpr bool foo(T&& t) {
t;
return false;
}
foo(a) is still a constant expression. Such cases are exceptions as the reference t is initialized within the evaluation of foo(a).
Related part in the standard (irrelevant part is elided by me):
[expr.const]/2:
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
...
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
it is initialized with a constant expression or
its lifetime began within the evaluation of e;
...
[expr.const]/6:
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), ...
An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.
Because you can't know at compile time what value x will have, all you know is that it will point to a. What you are doing is checking the "value" of x, but the value of x is the address where a is and you can't know where a will be allocated nor an address is constant.
On the other hand you already know the value of a, it's an empty std::string.
This question contains some more details: how to initialize a constexpr reference
Firstly, In your both code sections, the evaluation context all require the postfix-expression to be a constant expression. The definition of function template foo satisfies the requirements of a constexpr function due to its parameter is of literal type.
id-expression a and x are all glvalue which evaluation determine the identity of an object, but the only difference is that, In your fist code. copy-initialize the parameter from a only require identity conversion, because of the following rules:
When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion
And it does nothing, due to
[over.ics.scs#2]
As described in Clause [conv], a standard conversion sequence is either the Identity conversion by itself (that is, no conversion)
And the remain expressions are all constant expressions. So, for foo(a) this expression, it's a constant expression.
For foo(x), because x is an id-expression of reference type that subject to this rule:
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
it is initialized with a constant expression or
its lifetime began within the evaluation of e;
The lifetime of x began before the evaluation of foo(x) and it isn't initialized with a constant expression because std::string a; is not a glvalue constant expression. If you modify the std::string a; to static std::string a;,then it will be ok.