constexpr
contextsconstexpr
contextsstatic_assert
in a constexpr
function for an expression that's dependent on function parameters ("constexpr
" means "maybe this might be evaluated in a constant expression"). But you can just use assert
as usual
constexpr
mean?constexpr
mean?constexpr
you mean!constexpr
variables
constexpr
functions
constexpr
if statements (a.k.a., if constexpr
)
constexpr
uses require different things to be constant expressionsconstexpr
variables require constant initializers
constexpr
if statements require constant conditional expressions
constexpr
functions require ???
constexpr
mean (for a function)?Look at how we can use it...
constexpr
variable...
static_assert
...
constexpr
functions can be used with runtime parameters!
constexpr
mean? (And why?)constexpr
means maybe this might be evaluated in a constant expression"constexpr
function that never can be used in a constant expression is ill-formed:
assert
in a constexpr
function?constexpr
function from the earlier slide?
assert
macro is usually written something like this:
assert(expr())
is only a constant expression if expr()
evaluates to true
constexpr
really mean?"constexpr
functions and function templates in C++ generally speaking mean maybe constexpr
. Not all instantiations or evaluations must be invocable at compile time, it's just that there must be at least one set of function arguments in at least one instantiation that works."
...but this might change soon!
operator[]
with a Tuple
42
, 0x5A6DF3
, 123ull
, -123'456'789ll
42.0
, 42.
, 4.2e1
, 0xa.bp10f
, 0X0p-1
"hello"
, L"ABC"
, R"foo(hello world)foo"
'a'
, U'🍌'
, '\n'
true
, false
nullptr
25u or 17U
is a unsigned int
(larger values will have a larger type)25l or 17L
is a long int
(or larger for larger values)25uz or 17UZ
is a std::size_t
25z or 17Z
is a std::make_signed_t<std::size_t>
index
class template to hold the indices as non-type template parameters:
std::integral_constant
though)
std::get()
set()
function passes the value to impl()
and ignored the value that it expects impl()
to throw
impl()
stores its argument in a static variable during the initializer of another static variable _
and throw
s before that initializer can return
impl()
always runs stored = v;
in a thread-safe way every time it is called, since the initializer of _
never completes without an exception.
impl()
.
static
variables are not part of lambda capture. The reference to stored
is part of the type of the lambda on line 5 (rather than any particular instance).get()
effectively executes the body of the lambda in line 5 without ever executing line 4 👻
impl()
for each template parameter—and thus a unique instance of stored
and a unique lambda type for the returnset()
and get()
refer to the version of impl()
associated with a given template parameter