【问题标题】:Why constexpr data members are not implicitly static?为什么 constexpr 数据成员不是隐式静态的?
【发布时间】:2016-07-03 13:09:40
【问题描述】:

如果你这样做:

constexpr int LEN = 100;

LEN 变量定义为const,无需键入const 关键字。
它还有static存储,无需输入static关键字。

另一方面,如果我们在class中做同样的事情:

struct A{
   constexpr static int SIZE = 100;
};

SIZE 仍然定义为const,无需输入 const 关键字,

但是SIZE 不是static 数据成员。
您需要明确输入static。否则会出现编译错误。

问题是:
需要显式输入static 的原因是什么?

【问题讨论】:

    标签: c++11 language-lawyer constexpr


    【解决方案1】:

    static 在两种上下文中的含义不同:

    • 对于LENstatic表示“仅在本编译单元中可用”,所以只有内部链接。这是一个storage specifier
    • 对于A::SIZEstatic 表示“它是一个类成员”,因此不绑定到特定实例

    constexpr 在类上下文中可以引用实例或类成员或函数,因此编译器无法确定它是否为 staticie 是否绑定到特定实例。这与const 说明符的推理相同。但是,你可以想象,拥有一个非静态的constexpr 成员是没有意义的,所以它是被禁止的。示例:

    class A
    {
         int a;
         constexpr A(int value): a(value) {}
    
         // constexpr bound to a specific instance
         constexpr int getDouble() const
         {     return a*2;    }
    
         // constexpr not bound to a specific instance
         static constexpr int getDouble(int b)
         {     return b*2;    }
    }
    

    constexpr 在全局上下文中是指将在编译时计算的东西(或者,对于函数,如果不可能在编译时计算,它将被内联),因此不需要外部链接,因此可以比较作为static 全局变量或函数的行为(仅可比较,因为通过编译时计算或内联,您也不需要内部链接)

    constexpr int a = 5; // Will be replace everywhere by value
    
    /* If b is constexpr, calcul are done at compile time and result will be used
    * else double is inlined, so no need of linkage at all
    */
    constexpr int getDouble(int b)  
    {     return b * 2;     }
    

    【讨论】:

    • 你不能调用一个函数“double”(它是一个关键字)并且你不能在一个类中拥有非静态的 constexpr 数据成员。
    【解决方案2】:

    我认为您对 static 在全球范围内的含义感到困惑,您的问题是基于这种误解。

    LEN 变量定义为 const,无需键入 const 关键字。

    当然constexpr 暗示const,这不足为奇。

    它还有static存储,无需输入static关键字。

    注意全局变量总是有静态存储,因为它的生命周期是全局的。添加 static 关键字并不会改变这一点,它所做的是赋予它内部链接,这意味着它在当前翻译单元之外无法通过名称访问。

    constexprconst 在全局变量上的规则相同:命名空间范围的 const 变量隐含地具有内部链接(这是“静态”的众多含义之一)。

    但是类范围的 const 变量没有内部链接,即使您将 static 添加到它。标记变量static 意味着在命名空间范围和类范围完全不同。将static 自动添加到标记为constconstexpr 的类成员是没有意义的,因为这意味着与命名空间范围内的变量完全不同。

    所以constexpr 暗示const(很明显),并且在命名空间范围内const 暗示内部链接。

    在类作用域constexpr 仍隐含const,但这对成员变量是“类变量”还是“实例变量”没有任何影响。

    【讨论】:

    • 投了反对票,他的问题虽然措辞不好,但还是有道理的。如果某个东西是 constexpr 成员(在编译时初始化并在编译时已知),那么将其设为实例变量而不是类变量是没有意义的。因为让实例存储永远不变的相同值是愚蠢的。事实上,如果你错过了静态代码将无法编译(意味着它没有其他含义):错误:非静态数据成员'SIZE'声明'constexpr' constexpr int SIZE = 100;
    【解决方案3】:

    constexpr 不应暗示static,因为有constexpr 没有static 是有道理的。考虑:

    #include <iostream>
    
    struct Dim
    {
        constexpr Dim(int a,int b) : a(a), b(b) {}
        constexpr int Prod() const { return a*b; }
        int a,b;
    };
    
    int main()
    {
        constexpr Dim sz(3,4);
        int arr[ sz.Prod() ];
        std::cout << sizeof(arr) << std::endl;
    }
    

    它也不应该在类定义之外暗示static 因为static 意味着“本地翻译单元”和constexpr 不需要。

    【讨论】:

    • 在命名空间范围内,constexpr 并不完全暗示static,但它很接近。它暗示const,并且命名空间范围非易失性const变量默认具有内部链接(即static)。
    • 你能有 volatile const 变量吗?
    • @soandos:当然,您不能更改它们,但程序需要每次都读取它们,因为硬件可能会更改值。 (例如)
    猜你喜欢
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    • 2016-10-15
    • 2016-12-16
    • 1970-01-01
    相关资源
    最近更新 更多