我正在阅读有关将引用绑定到静态数据成员或获取其地址的信息,前提是(且仅当)引用具有类外定义 (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;
,它会生成错误(并非如此)(编译并运行OK)。
所以我有2个问题:
const int* p1 = &AE::c6;
,这不是我所期望的?答案 0 :(得分:3)
对于第一个问题,在常量名称前面添加+
会将值从常量更改为表达式。表达式的结果存储在一个未命名的临时变量中,并将对该临时变量的引用传递到byref
。如果没有+
,则直接引用该常量,这要求该常量在程序中的某个位置具有定义。
对于第二个问题,编译器不会在编译过程中发出诊断信息,因为AE::c6
的一个定义可能存在于另一个源文件中。找不到定义时,链接器将提供错误。
[class.static.data]中的语言标准说:“在程序中应该有一个静态数据成员的确切定义(6.2);没有 因此,没有定义或不止一个定义是一种违规,但是不需要报告。在前一种情况下,编译器/链接器可以创建要使用的定义,而在后一种情况下,链接器将只选择可用的定义之一。