【问题标题】:static const double cannot have an in-class initializer. why is it so?static const double 不能有类内初始化程序。为什么会这样?
【发布时间】:2012-11-21 17:54:19
【问题描述】:

以下代码的问题是“const double”类型的静态成员不能具有类内初始化程序。为什么仅适用于以下代码中的“const double”?请帮帮我。

class sample{
   static const char mc = '?';
   static const double md = 2.2;
   static const bool mb = true;
};
const char sample::mc;
const double sample::md;
const bool sample::mb;
int main(){
}

【问题讨论】:

    标签: c++


    【解决方案1】:

    C++03语言标准实现的逻辑基于以下基本原理。

    在 C++ 中,initializer 是对象定义 的一部分。您在类中为静态成员编写的内容实际上只是一个声明。因此,正式地说,直接在类中为任何静态成员指定初始化程序是“不正确的”。它与语言的一般声明/定义概念相反。无论您在类中声明什么静态数据都必须在以后定义。这就是您有机会指定初始化程序的地方。

    此规则的一个例外是静态整型常量,因为 C++ 中的此类常量可以形成整型常量表达式 (ICE)。 ICE 在语言中发挥着重要作用,为了让它们按预期工作,整数常量的值必须在所有翻译单元中可见。为了使某个常量的值在所有翻译单元中可见,它必须在声明处可见。为了实现这一点,该语言允许直接在类中指定初始化器。

    此外,在许多硬件平台上,常量整数操作数可以直接嵌入到机器命令中。或者可以完全消除或替换常数(例如,乘以8 可以实现为移位3)。为了便于生成具有嵌入式操作数和/或各种算术优化的机器代码,让整数常量的值在所有翻译单元中可见是很重要的。

    非整数类型没有任何类似于 ICE 的功能。此外,硬件平台通常不允许将非整数操作数直接嵌入到机器命令中。出于这个原因,上述“规则的例外”不会扩展到非整数类型。它只会一事无成。

    【讨论】:

    • 为什么双打的规则没有这样的例外?将浮动常量嵌入到机器命令中没有意义吗?
    • @anton_rh:问得好。我不知道为什么纯粹从概念上不允许它。至于实际考虑,大多数平台根本无法嵌入浮点常量(现在仍然不能)。造成这种情况的一个原因可能是浮点常量对于这种嵌入来说太大了。但是,在 C++11 中,constexpr 至少在概念上允许您绕过该限制。
    【解决方案2】:

    编译器让我使用constexpr 而不是const

    static_consts.cpp:3:29: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive]
    static_consts.cpp:7:22: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive]
    

    我刚刚接受了这个提议:

    class sample{
       static const char mc = '?';
       static constexpr double md = 2.2;
       static const bool mb = true;
    };
    const char sample::mc;
    const bool sample::mb;
    int main(){
    }
    

    现在它编译得很好 (C++11)。

    【讨论】:

    • 你的编译器比我的编译器(MSVC++)更有帮助!
    • 很好的答案。正是我想要的。谢谢。
    • 这并不能解释为什么 static const 必须是整数类型。只是新版本的 c++ 允许 static constexpr 双打。
    【解决方案3】:

    C++11之前,只有const整数类型可以在类定义中直接初始化。这只是标准强加的限制。

    对于 C++11,这不再适用。

    【讨论】:

    • 实际上,按照[class.static.data]p3,static数据仍然可以在类定义中初始化,只有当它是非易失的const的整数或枚举类型。跨度>
    • @Angew 你在说“它在类定义中的声明可以指定一个大括号或等号初始化器,其中每个作为赋值表达式的初始化器子句都是一个常量表达式”。因为那是不同的——它是关于大括号初始化的。
    • 这有什么不同?根据 [dcl.init],brace-or-equal-initializer ::= = initializer-clause | braced-init-list
    • 仍然无法使用 C++11 编译器甚至使用 C++14 编译器编译此代码。
    • @Luchian Grigore:只要我们专门讨论static const,C++11 就没有变化。在这方面,静态成员的规则几乎保持不变。 static const double 仍然无法在类中初始化,即使在 C++14 中也是如此。 constexpr 是另一回事 - 它支持立即初始化器。
    猜你喜欢
    • 2020-05-29
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多