Reputation: 400
Take a look at the following code example:
template<bool val>
struct test {
static const int value_a = val;
const int value_b = val;
constexpr int get_value_a() const noexcept { return value_a; }
constexpr int get_value_b() const noexcept { return value_b; }
};
int main(int argc, char** argv) {
auto t = test<true>{};
static_assert(t.value_a);
// static_assert(t.value_b);
static_assert(t.get_value_a());
// static_assert(t.get_value_b());
}
Both gcc and clang agree that this should compile, but including any of the commented out static asserts makes it invalid. For example, gcc would then produce these error messages:
error: non-constant condition for static assertion
error: the value of ‘t’ is not usable in a constant expression
note: ‘t’ was not declared ‘constexpr’
This makes perfect sense to me and is exactly what I would have thought. But I don't really know why the other two static asserts compile in the first place. What is the relevant paragraph from the standard that allows this?
In particular, how is this formalized? Is there a clearly defined difference between just using a variable, versus actually accessing its runtime value (which then would be the only forbidden thing in a constexpr context)?
Upvotes: 2
Views: 477
Reputation: 5095
In particular, how is this formalized?
http://eel.is/c++draft/expr.const#4.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:
this
([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of e;
Access to non-static members evaluates the this
pointer. Access to a static member does not.
Upvotes: 0
Reputation: 40891
It's just the rules. Before constexpr
, const
variables initialised with constant expressions could be used as constant expressions themselves (Also for some compatibility with C)
From the standard [expr.const]/3
:
A variable is usable in constant expressions after its initializing declaration is encountered if [...] it is a constant-initialized variable [...] of const-qualified integral or enumeration type.
This wouldn't extend to const auto t = test<true>{}
because test<true>
is not an integral type (You would need to have constexpr auto t = test<true>{}
, as expected, following the rules of the rest of that paragraph)
Upvotes: 1