constexpr: definition and declaration for constexp

2019-01-29 07:08发布

问题:

If I want to use some convenience stuff like make_array I have no chance to declare my array first and later make the definition as done in "earlier" times because the type of my var is not available before definition.

So I found this answer:
Undefined reference to static constexpr char[]

In the following example I wrote this solution which compiles fine with gcc and I am not sure that this is really valid c++ code, because it is more or less a declaration with definition and later a definition without any content. Is this allowed? ( Compiles fine is not a guarantee that the code is valid c++ )

#include <experimental/array>
#include <iostream>

class Foo
{
    private:
    static decltype(auto) constexpr Bar =
        std::experimental::make_array(
            std::experimental::make_array( 1,2,3 ),
            std::experimental::make_array( 4,5,6 )
            );

    public:
    using ARR_TYPE = decltype( Bar );

    static auto& GetArr( int idx )
    {
        // range check ...
        return Bar[idx];
    }
};

constexpr Foo::ARR_TYPE Foo::Bar;

int main()
{
    for ( auto el: Foo::GetArr(0))
    {
        std::cout << el << std::endl;
    }
 }

回答1:

The rules governing static constexpr members changes in C++1z, which is kinda annoying.

Pre C++1z

From [class.static.data]

[...] 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. [...] The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer.

Which means you are required to provide a initializer in the declaration, but also to provide a definition at namespace scope without an initializer.

Your code does exactly that.

Post C++1z

From the same paragraph [class.static.data]

[...] If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see [depr.static_constexpr]). [...]

And from [depr.static_constexpr]

For compatibility with prior C++ International Standards, a constexpr static data member may be redundantly redeclared outside the class with no initializer. This usage is deprecated.

So, this is still legal, but deprecated.

It should be noted static but not constexpr members (including static const members) are still required to have a definition in namespace scope if it is odr-used.