【问题标题】:sizeof in static const member initialization静态 const 成员初始化中的 sizeof
【发布时间】:2018-11-28 13:19:57
【问题描述】:

我有这样的代码:

class A
{
public:

    unsigned long a;
    static const unsigned long b = sizeof(a); // "error C2327: 'A::a' : is not a type name, static, or enumerator" in VC++
};

我在 VC++ 中遇到编译器错误,而在 IAR 中没有错误。 哪个编译器是正确的,C++ 标准对此有何评论?

【问题讨论】:

  • 您使用的是哪个 MSVC 版本?
  • MSVS 2013 和 MSVS 2005。
  • 我想这意味着您使用的是最新版本的 IAR... 而不是最新版本的 VS2005...。

标签: c++ visual-studio-2013 visual-studio-2005 sizeof member-variables


【解决方案1】:

您的 MSVS 版本非常旧,因此基于此,假设它们默认为 C++03,它们拒绝您的代码是正确的。我将引用 n1905,就我们的目的而言,它非常接近 C++03 标准。

9.4 [class.static](强调我的)

如果在静态定义中使用了 unqualified-id (5.1) 成员声明符 id 之后的成员和名称查找 (3.4.1) 发现 unqualified-id 引用静态成员、枚举器、 或成员类的嵌套类型(或 member's class), unqualified-id 转换为qualified-id 嵌套名称说明符命名类范围的表达式 从中引用该成员。 静态成员的定义 不得直接使用其非静态成员的名称 类或其类的基类(包括作为 sizeof 运算符)。静态成员的定义只能参考 这些成员形成指向成员的指针(5.3.1)或与类 成员访问语法 (5.2.5)。

【讨论】:

    【解决方案2】:

    StoryTeller's answer 指定了为什么这不适用于。即因为直到 才支持它。

    而言,它完全符合。但我已经验证了这段代码可以解决这个缺陷:

    static const unsigned long b = sizeof(decltype(a))
    

    如果您还想要与 一起使用的东西,请考虑将 b 设为全局成员,而不是 A 的静态成员:

    const unsigned long b = sizeof(A().a)
    

    【讨论】:

    • 关键字是应该。而且我不确定 C++11 是当时 MSVC2013 的默认标准。
    • 根据this source,即使在MSVC2015中也不完全支持C++11。
    • @AlgirdasPreidžius 你没看错......即使是 VS2015 也有一些突出的 C++11 缺陷。或者我应该只说 C++ 标准缺陷 :( 为了清楚起见,我将重新措辞。我试图传达的是 sizeof(a) 现在实际上是有效的代码......这只是 Visual Studio 的差异导致它无法编译.
    • @StoryTeller 是的,我已经澄清了。正如已经指出的那样,VS2013 甚至没有声称与 C++11 兼容。
    【解决方案3】:

    staticconst-qualified 使用非static 成员的类内初始化程序直到 C++11 才成为 C++ 标准的一部分。

    最早完全支持C++11的MSVC编译器是MSVC2017。

    那个编译器会正确编译你的代码。

    【讨论】:

    • 我相信这是正确的(尽管我没有 VS2015 可以检查。)我只是想不通微软给这部分规范的功能名称,所以我不能在获得支持的时间表上找不到任何权威的东西。 decltype can be used to workaround this deficiency circa VS 2012。所以我真的很想了解这个限制......如果你可以提供一个链接来获取你的陈述,那么值得为你 +1!
    • @JonathanMee:非正式地,您可以在编译器上检查 __cplusplus 的值:MSVC2017 是最早具有 C++11 值的版本。在整数算术中可能只值 1/2 ;-)
    【解决方案4】:

    你有什么?

    您有一个名为Aclass 的定义。

    您的班级一个名为 unsigned longa

    您的班级一个名为 static const unsigned longb

    在某些 C++ 编译器中,class静态非静态成员不能混用,尤其是在定义阶段。

    你想要什么?

    static const unsigned long b = sizeof(unsigned long);
    

    这并不完全是你想要的,但这是一个聪明的编译器试图弄清楚的方式。

    为什么???

    因为静态成员不会将其范围限制在对象定义中。它们超越了对象范围,可以从任何地方访问,例如,只需在控制台中使用std::cout << A::b << std::endl 输出A::b

    Clang 不接受这种结构,GCC 接受(都带有-g -std=c++98

    MSVC 19.14 (visual studio 15.7) 也不接受它,但带有 MSVC 19.15 的 Visual Studio 15.8 可以。

    谨慎选择。

    我在哪里检查所有这些东西?

    在这里我检查了很多编译器:https://godbolt.org/ 这是一种方法,但您以后必须避免这种黑客攻击。

    检查和责备的魔法代码

    归咎于混合 C 和 C++。它仅用于与旧版本一起编译,无需任何检查:

    #include <stdio.h>
    
    class A
    {
    public:
    
        unsigned long a;
        static const unsigned long b = sizeof(a); // "error C2327: 'A::a' : is not a type name, static, or enumerator" in VC++
    };
    
    int main (void)
    {
        printf ( "Hello World" ); // I strongly not recommend using printf's in C++ code. 
        printf ( "%d", A::b );    // This is only to fill a functional example, not a rightful one.
        return 0;
    }
    

    【讨论】:

    • 这个答案确实提供了一些间接证据证明哪种行为是正确的。因此,我对有人在这里投反对票的事实感到难过,尤其是在为这个答案付出了这样的努力时。所以有一个 +1。
    • 我对投反对票并不感到难过。我感觉很好,有人可以阅读并理解它,即使他们投反对票或投赞成票。标准不是现实世界,但那里的编译器才是。
    猜你喜欢
    • 1970-01-01
    • 2012-02-02
    • 2013-04-13
    • 1970-01-01
    • 2018-08-03
    • 2011-03-19
    • 2011-04-01
    • 1970-01-01
    相关资源
    最近更新 更多