【问题标题】:constexpr: definition and declaration for constexpr membersconstexpr:constexpr 成员的定义和声明
【发布时间】:2017-06-23 12:41:24
【问题描述】:

如果我想使用像make_array 这样的方便的东西,我没有机会先声明我的数组,然后在“早期”时间进行定义,因为我的 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;
    }
 }

【问题讨论】:

    标签: c++ static language-lawyer constexpr


    【解决方案1】:

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

    Pre C++1z

    来自[class.static.data]

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

    这意味着您需要在声明中提供初始化程序,而且还需要在命名空间范围内提供定义没有初始化程序。

    您的代码正是这样做的。

    发布 C++1z

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

    [...] 如果成员使用 constexpr 说明符声明,则它可以在没有初始化程序的命名空间范围内重新声明(此用法已弃用;请参阅 [depr.static_constexpr])。 [...]

    来自[depr.static_constexpr]

    为了与以前的 C++ 国际标准兼容,constexpr 静态数据成员可能会在没有初始化程序的类外部冗余地重新声明。这种用法已被弃用。

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

    需要注意的是static而不是constexpr成员(包括static const成员)如果被odr使用,仍然需要在命名空间范围内有定义。

    【讨论】:

    • 很高兴听到我们不再需要重新声明!我检查了 gcc 7.1.0/C++17,是的,我可以简单地删除定义。所以我会把我所有的项目都切换到 c++17 :-) 语言是正确的!
    猜你喜欢
    • 2014-02-25
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 2012-10-24
    • 2013-10-12
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多