constexpr initializing static member using static function

前端 未结 4 2104
鱼传尺愫
鱼传尺愫 2020-11-27 22:14

Requirements

I want a constexpr value (i.e. a compile-time constant) computed from a constexpr function. And I want both of these scoped

4条回答
  •  爱一瞬间的悲伤
    2020-11-27 22:44

    1) Ilya's example should be invalid code based on the fact that the static constexpr data member bar is initialized out-of-line violating the following statement in the standard:

    9.4.2 [class.static.data] p3: ... A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression.

    2) The code in MvG's question:

    class C1 {
      constexpr static int foo(int x) { return x + 1; }
      constexpr static int bar = foo(sizeof(int));
    };
    

    is valid as far as I see and intuitively one would expect it to work because the static member foo(int) is defined by the time processing of bar starts (assuming top-down processing). Some facts:

    • I do agree though that class C1 is not complete at the point of invocation of foo (based on 9.2p2) but completeness or incompleteness of the class C1 says nothing about whether foo is defined as far as the standard is concerned.
    • I did search the standard for the definedness of member functions but didn't find anything.
    • So the statement mentioned by Ben doesn't apply here if my logic is valid:

      an invocation of an undefined constexpr function or an undefined constexpr constructor outside the definition of a constexpr function or a constexpr constructor;

    3) The last example given by Ben, simplified:

    class C1
    {
      constexpr static int foo() { return bar; }
      constexpr static int bar = foo();
    };
    

    looks invalid but for different reasons and not simply because foo is called in the initializer of bar. The logic goes as follows:

    • foo() is called in the initializer of the static constexpr member bar, so it has to be a constant expression (by 9.4.2 p3).
    • since it's an invocation of a constexpr function, the Function invocation substitution (7.1.5 p5) kicks in.
    • Their are no parameters to the function, so what's left is "implicitly converting the resulting returned expression or braced-init-list to the return type of the function as if by copy-initialization." (7.1.5 p5)
    • the return expression is just bar, which is a lvalue and the lvalue-to-rvalue conversion is needed.
    • but by bullet 9 in (5.19 p2) which bar does not satisfy because it is not yet initialized:

      • an lvalue-to-rvalue conversion (4.1) unless it is applied to:
        • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression.
    • hence the lvalue-to-rvalue conversion of bar does not yield a constant expression failing the requirement in (9.4.2 p3).

    • so by bullet 4 in (5.19 p2), the call to foo() is not a constant expression:

      an invocation of a constexpr function with arguments that, when substituted by function invocation substitution (7.1.5), do not produce a constant expression

提交回复
热议问题