static constexpr member of same type as class being defined

后端 未结 3 1727
故里飘歌
故里飘歌 2020-11-29 04:17

I would like a class C to have a static constexpr member of type C. Is this possible in C++11?

Attempt 1:

struct Foo {
    constexpr Foo() {}
    sta         


        
相关标签:
3条回答
  • 2020-11-29 04:58

    An update on Richard Smith's answer, attempt 3 now compiles on both GCC 4.9 and 5.1, as well as clang 3.4.

    struct Foo {
      std::size_t v;
      constexpr Foo() : v(){}
      static const Foo f;
    };
    
    constexpr const Foo Foo::f = Foo();
    
    std::array<int, Foo::f.v> a;
    

    However, when Foo is a class template, clang 3.4 fails, but GCC 4.9 and 5.1 still work ok:

    template < class T >
    struct Foo {
      T v;
      constexpr Foo() : v(){}
      static const Foo f;
    };
    
    template < class T >
    constexpr const Foo<T> Foo<T>::f = Foo();
    
    std::array<int, Foo<std::size_t>::f.v> a; // gcc ok, clang complains
    

    Clang error :

    error: non-type template argument is not a constant expression
    std::array<int, Foo<std::size_t>::f.v> a;
                    ^~~~~~~~~~~~~~~~~~~~~
    
    0 讨论(0)
  • 2020-11-29 05:00

    If I interpret the Standard correctly, it isn't possible.

    (§9.4.2/3) [...] 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. [...]

    From the above (along with the fact that there is no separate statement about non-literal types in static data member declarations), I believe it follows that a static data member that is constexpr must be a literal type (as defined in §3.9/10), and it must have its definition included in the declaration. The latter condition could be satisfied by using the following code:

    struct Foo {
      constexpr Foo() {}
      static constexpr Foo f {};
    };
    

    which is similar to your Attempt 1, but without the class-external definition.

    However, since Foo is incomplete at the time of declaration/definition of the static member, the compiler can't check whether it is a literal type (as defined in §3.9/10), so it rejects the code.

    Note that there is this post-C++-11 document (N3308) which discusses various problems of the current definition of constexpr in the Standard, and makes suggestions for amendments. Specifically, the "Proposed Wording" section suggests an amendment of §3.9/10 that implies the inclusion of incomplete types as one kind of literal type. If that amendment was to be accepted into a future version of the Standard, your problem would be solved.

    0 讨论(0)
  • 2020-11-29 05:06

    I believe GCC is incorrect to reject your Attempt 3. There is no rule in the C++11 standard (or any of its accepted defect reports) which says that a redeclaration of a variable must be constexpr iff the prior declaration was. The closest the standard comes to that rule is in [dcl.constexpr](7.1.5)/1_:

    If any declaration of a function or function template has constexpr specifier, then all its declarations shall contain the constexpr specifier.

    Clang's implementation of constexpr accepts your Attempt 3.

    0 讨论(0)
提交回复
热议问题