为什么“int const B::bsm1a;"不被认为是重新定义? [英] Why "int const B::bsm1a;" not considered a redefinition?

查看:19
本文介绍了为什么“int const B::bsm1a;"不被认为是重新定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#include <iostream>
struct B {
public:
    static int const bsm1a{ 0xf };
};
int const B::bsm1a; // 1) Why is this NOT considered a redefinition?
                    // 2) What does this line actually do here?

int main()
{
    std::cout << "Hello World!\n";
}

#include <iostream>
struct B {
public:
    static int const bsm1a{ 0xf };
    static int const bsm1a; // Considered as a redefinition here and throws error C2086
};

int main()
{
    std::cout << "Hello World!\n";
}

我的问题(嵌入在上面的代码中):

My questions (embedded above in the code):

  1. 为什么这不被视为重新定义?
  2. 这条线实际上在这里做什么?

推荐答案

这是我在阅读 C++ 标准时收集到的信息.如果我的解释有误,请纠正我.

在第一种情况下,情况相当有趣.这归结为C++中declarationdefinition的含义.如果您深入研究 C++ 标准,您将找到本主题的一部分:

In the first case the situation is rather interesting. This comes down to the meaning of of declaration and definition in C++. If you dig into the C++ Standard, you'll find a section of this topic:

(§6.2) 声明声明的每个实体也由声明定义,除非:

(§6.2) Each entity declared by a declaration is also defined by that declaration unless:

(§6.2.3) 它在类定义 (11.4, 11.4.8) 中声明了一个非内联静态数据成员

(§6.2.3) it declares a non-inline static data member in a class definition (11.4, 11.4.8)

这告诉我们 static int const bsm1a{ 0xf }; 这行不是定义而是声明.

This tells us that the line static int const bsm1a{ 0xf }; is not a definition but a declaration.

过去不允许在类中定义 static const 数据成员,因为当静态成员是类定义的一部分并包含在多个不同的翻译单元中时,它会违反一个定义规则(你现在可以使用 inline 变量在 C++17 之后执行此操作).所以以前的写法是

Defining static const data members inside a class used to disallowed because when the static member was part of a class definition and got included in multiple different translation units, it would violate the One Definition Rule (You can now do it post-C++17 using inline variables). So the way this used to be written was

struct Foo {
public:
    static const std::string str; //Declaration
};
const std::string Foo::str = "Hello World\n"; //Definition

但是,根据 §11.4.8.2.4 允许在类定义中声明整型或枚举类型的 static const 变量

However, it is allowed to declare a static const variable of integral or enumeration type inside a class definition per §11.4.8.2.4

如果一个 non-volatile 非内联 const 静态数据成员是整数或枚举类型,它在类定义中的声明可以指定一个 brace-or-equal-initializer,其中每个 initializer-clause 是一个赋值表达式 是一个常量表达式

If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression

static int const bsm1a{ 0xf }; 符合该描述,因此是允许的,但它仍然是一个声明.

static int const bsm1a{ 0xf }; fits that description and thus it is allowed, but it is still a declaration.

此时,B::bsm1a 已声明但未定义.您可以给它一个整数或 enum 的值,因为编译器可以将其放入寄存器中,而不会实际为其分配内存.

At this point, B::bsm1a is declared but not defined. You can give it a value that's an integer or an enum because the compiler can put this into a register and never actually allocate memory for it.

#include <iostream>

struct B {
    static const int bsm1a{0xf}; // Compiler keeps track of the 0xf internally
};

int main()
{
    std::cout << &B::bsm1a << "\n"; //Whoops, this is not defined and there is no memory allocated to it, so taking its address is impossible (you'll get a linker error)
}

当您注释掉 std::cout 并检查程序集时,有没有对 B::bsm1a 的引用.当您稍后编写 int const B::bsm1a; 时,这不是声明而是定义.只有在这一点上,变量才被定义并且内存被分配给它.当您检查下面的代码汇编时,您将看到现在15"出现在最终程序集中并调用 &B::bsm1a 实际寻址其内存位置 (movl $B::bsm1a, %esi)

When you comment out the std::cout and examine the assembly, there is no reference to the B::bsm1a. When you later write int const B::bsm1a; this is not a declaration but a definition. Only at this point does the variable become defined and memory is allocated to it. When you examine the assembly of the code below, you will see that now "15" appears in the final assembly and call to &B::bsm1a actually addresses its memory location (movl $B::bsm1a, %esi)

#include <iostream>

struct B {
    static const int bsm1a{0xf}; 
};
const int B::bsm1a; // It is now defined and has memory assigned to it

int main()
{
    std::cout << &B::bsm1a << "\n"; // We can now take its address
}

在第二种情况下,您还有另一个问题.

In the second case you have another issue.

(§11.4.5) 一个成员不得在成员规范中被声明两次,除非

(§11.4.5) A member shall not be declared twice in the member-specification, except that

(§5.1) 可以声明嵌套类或成员类模板,然后再定义,并且(第 5.2 节)可以使用 opaque-enum-declaration 引入枚举,然后使用 enum-specifier 重新声明.

(§5.1) a nested class or member class template can be declared and then later defined, and (§5.2) an enumeration can be introduced with an opaque-enum-declaration and later redeclared with an enum-specifier.

除非满足这两个条件,否则您根本不允许在类成员规范中重新声明它.例如,以下是合法的:

You are simply not allowed to redeclare it within the class member-specification unless it meets those two criteria. So for example the following would be legal:

struct Foo
{
public:
    struct X; // declaration
    struct X; // redeclaration, allowed
};

但由于您的 static const int 不是这些类型之一,这是非法的.

But since your static const int is not one of the these types, this is illegal.

这篇关于为什么“int const B::bsm1a;"不被认为是重新定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆