为什么“int const B::bsm1a;"不被认为是重新定义? [英] Why "int const B::bsm1a;" not considered a redefinition?
问题描述
#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):
- 为什么这不被视为重新定义?
- 这条线实际上在这里做什么?
推荐答案
这是我在阅读 C++ 标准时收集到的信息.如果我的解释有误,请纠正我.
在第一种情况下,情况相当有趣.这归结为C++中declaration
和definition
的含义.如果您深入研究 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屋!