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