问题描述
有很多关于 constexpr 表达式的问题/答案,但我有一个与其他问题非常接近但在另一种意义上略有不同的问题。无论如何,它就在这里。
#include <iostream>
using namespace std;
constexpr int x = 1; // TAG A
int main() {
constexpr int &xf = x; // TAG B error out
const int &xf1 = x; // TAG C works
constexpr int const &xf2 = x; // TAG D works
return 0;
}
错误:
Binding reference of type 'int' to value of type 'const int' drops 'const' qualifier [reference_bind_drops_quals]
评论:
- TAG A 清楚地表明 x 是 const int。根据 C++ Primer 第 5 版第 2.44 页“变量 声明为 constexpr 是隐式 const 并且必须由常量初始化 表达:“。所以这很好。
- TAG B --> 错误消息暗示 constexpr 没有隐式“const”变量 xf。因此 xf 是 int &。这与 TAG A 矛盾。为什么?
- TAG C --> 这是对 const 的常用引用
- TAG D --> 由于它在 TAG B 中的行为方式,添加了额外的“const”以使其成为 const 引用。
“引用常量”和“常量引用”这两个词有区别吗?
似乎对 const 的引用意味着引用是指一个 const 对象,但不允许进行修改,而“const 引用”是指该引用是 const 但它可以指向 const 或非 const 对象。
这是一件令人困惑的大事。
解决方法
B 中的 constexpr
指的是变量 xf
,而不是类型(int & constexpr xf;
,虽然我不知道它是否会编译)。变量 xf
是一个 constexpr
,它的类型为 int &
。这就是尝试将其绑定到 x
失败的原因。
“引用常量”和“常量引用”这两个词有区别吗
是的,从概念上讲,但“const 引用”在逻辑上折叠为“引用”,因为从技术上讲,所有引用都是常量。这也是该语言不允许您将引用声明为显式 <mat-table [dataSource]="alertCounts">
...
</mat-table>
的原因。 话虽如此,在语言中仍有一些情况可以讨论“const 引用”。考虑以下示例:
const
在这种情况下,typedef int &intref;
int main() {
int x = 0;
const intref xf = x;
return 0;
}
实际上是一个 const 引用(不是对 const 的引用),并且声明仍然有效。这会给你一个关于 const 限定符被忽略的警告,但它仍然会编译和运行。这说明了为什么严格遵守声明顺序规则仍然很重要。
要理解此声明的下一个非常重要的信息是 xf
关键字的应用,以及当我们说它“隐含 constexpr
”时它的确切含义。 const
关键字始终指的是声明中的对象(而不是类型),因此当我们说 constexpr
隐含 constexpr
时,这意味着从某种意义上说,您可以省略const
关键字位于 const
声明(在本例中为 constexpr
)的最内部部分,因为它是多余的。在引用的特殊情况下,它不仅是多余的,而且是不允许的。您可能会争辩说编译器抛出错误是不必要的,因为您可以使用 typedef 来解决它,但该原则仍然适用,就像应用缺失的 xf
的规则一样。
将所有这些放在一起,在您的示例中,您可以像以下内容一样大声读出声明 B:
“xf 是一个 constexpr,它是对整数的引用(根据定义为 const,因此无需暗示为 const)。”
但是这里我们有一个问题,因为我们试图声明一个对非常量对象的引用并将其分配给一个常量对象。这正是编译器所抱怨的。
另见this。