x432ph
x432ph

Reputation: 400

Non-constexpr variable sometimes usable in a constexpr context?

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

Answers (2)

n314159
n314159

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

Artyer
Artyer

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

Related Questions