Constant expressions¶
There are expressions in Ü, that are named constant expressions, which value may be calculated in compile-time.
Such expressions may be used in some places where it is necessary - for array sizes, for template arguments, in constructions like static_assert
and static_if
.
An expression may be constant if:
- All variables inside it are constant
- Functions and operators in this expression are
constexpr
.
constexpr types¶
Variables inside constant expressions should be constant.
Constant can be only variables of one of constexpr
types.
constexpr
types are:
- All fundamental types
- All enums
- All function pointers
- Arrays with
constexpr
element types - Tuples with all element types
constexpr
- Some struct types
constexpr
structs requirements:
- All field types should be
constexpr
- There should be no mutable reference fields
- There should be no explicit copy-constructors, copy-assignment operators, destructors
constexpr functions¶
Functions that may be used in constant expressions should be marked with constexpr
keyword.
Such functions should have a body, constexpr
for prototype declarations is not allowed.
constexpr
function requirements:
- Parameter types and return types should be
constexpr
, but not function pointers - They can’t be marked as
unsafe
- They should not contain
unsafe
blocks - They should not do reference pollution (see corresponding chapter)
- They can’t contain definitions of variables of non-
constexpr
types - They can’t contain calls to non-
constexpr
functions - They can’t call functions via pointers
constexpr
functions may have mutable reference parameters, but such functions can’t be called with constexpr
arguments in order to produce constexpr
result.
Almost all constructions are allowed inside constexpr
functions (except some forbidden ones) this includes conditions, loops, halt
, etc.
constexpr
function example:
fn constexpr ArrSumm( [ u32, 16 ]& arr ) : u32
{
auto mut res= 0u;
auto mut i= 0s;
while( i < 16s )
{
res+= arr[i];
++i;
}
return res;
}
constexpr variables¶
Immutable variables of constexpr
type which are constantly-initialized are considered to be constexpr
.
If it’s necessary to ensure that a variable is constexpr
, constexpr
mutability modifier should be used.
auto x= 0; // Variable is immutable, its initializer is constant, thus variable is constexpr
auto imut y= x + 5; // Same as above, but variable is explicitly marked as immutable
var i32 z(66), imut v(-5), w= y / 2; // All these variables are constexpr
var [ i32, 2 ] arr[ 0 + z, w * 10 ]; // These are constexpr too
auto constexpr x_copy= x; // Explicitly specify constexpr
var i32 constexpr ensure_constant(y); // Explicitly specify constexpr
var i32 mut nonconst= 0; // Initializer is constant, but the variable itself isn't because it is mutable
auto constexpr wtf= nonconst; // An error will be generated - initializer of constexpr variable is not constexpr