引用静态数据成员

referencing static data member

本文关键字:数据成员 静态 引用      更新时间:2023-10-16

我正在阅读有关绑定对静态数据成员的引用或获取其地址的内容,如果(且仅当(它具有类外定义(https://isocpp.org/wiki/faq/classes-and-objects#in-class-constant(。

当我尝试测试该示例(见下文(时,我注意到它可以在Visual Studio 2017上运行(没有预期的错误(。

我尝试使用在线编译器,但只收到一个错误(不是预期的两个(。

#include <iostream>
using namespace std;
class AE {  
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
void byref(const int& a);

int main(int argc, char* argv[])
{   
byref(AE::c6); // error: c6 not an lvalue
byref(AE::c7); // ok
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
std::cout << "p1 " << *p1 << "n";
std::cout << "p2 " << *p2 << "n";
return 0;
}
void byref(const int & a)
{
std::cout << a << "n";
}

暂时忽略Microsoft编译器...

在编译这个程序时,我得到了undefined reference to AE::c6,在堆栈更改为byref(+AE::c6);时发现了一个小技巧,可以解决它。

但是对于另一行const int* p1 = &AE::c6;如注释所示,它将生成一个错误,但事实并非如此(它编译并运行正常(。

所以我有两个问题:

  1. 这里的一元+角色是什么?
  2. 为什么编译器忽略了错误const int* p1 = &AE::c6;,这与我预期不同?

对于第一个问题,在常量名称前面添加+会将值从常量更改为表达式。 表达式的结果将存储到一个未命名的临时变量中,并且对该临时变量的引用将传递给byref。 如果没有+,则直接引用常量,这要求常量在程序中的某个地方有一个定义。

对于第二个问题,编译器不会在编译期间发出诊断,因为AE::c6的一个定义可能存在于不同的源文件中。 链接器在找不到定义时会提供错误。

[class.static.data] 中的语言标准说:"在程序中,应该只有一个 odr 使用的静态数据成员的定义 (6.2(;不 需要诊断。 因此,没有定义或有多个定义是一种违规行为,但不需要报告。 在前一种情况下,编译器/链接器可以创建要使用的定义,而在后一种情况下,链接器将只选择一个可用的定义。