constexpr:constexpr成员的定义和声明

时间:2017-06-23 12:41:24

标签: c++ static language-lawyer constexpr

如果我想使用像make_array这样的便利之类的东西,我没有机会先声明我的数组,然后在"之前的#34;中完成定义。时间因为我的var的类型在定义之前不可用。

所以我找到了这个答案:
Undefined reference to static constexpr char[]

在下面的例子中,我写了这个用gcc编译好的解决方案,我不确定这是非常有效的c ++代码,因为它或多或少是一个带有定义的声明,后来是一个没有任何内容的定义。这是允许的吗? (编译罚款不能保证代码有效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 个答案:

答案 0 :(得分:4)

管理static constexpr成员的规则在C ++ 1z中发生了变化,这有点令人讨厌。

Pre C ++ 1z

来自[class.static.data]

  

[...]文字类型的静态数据成员可以使用constexpr说明符在类定义中声明;如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。 [...] 如果程序中使用了odr-used ([basic.def.odr]),则成员仍应在命名空间范围内定义,并且命名空间范围定义不应包含初始化程序

这意味着您必需在声明中提供初始值设定项,但也提供命名空间范围的定义,而无需初始值设定项。

您的代码正是如此。

Post C ++ 1z

来自同一段[class.static.data]

  

[...]如果使用constexpr说明符声明成员,则可以在没有初始值设定项的命名空间范围内重新声明(不推荐使用此用法;请参阅[depr.static_constexpr])。 [...]

来自[depr.static_constexpr]

  

为了与先前的C ++国际标准兼容,constexpr静态数据成员可以在课外冗余重新声明而不使用初始化程序。不推荐使用此用法。

所以,这仍然是合法的,但已被弃用。

应该注意static但是constexpr成员(包括static const成员)仍然需要在命名空间范围内有一个定义,如果它是使用过的。