C++:constexpr 隐含的将变量声明为常量并不适用于引用。

3

有很多关于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]

评论:

  1. 标签A清楚地显示x为const int。根据C++ Primer第5版第2.44节“声明为constexpr的变量隐式为const,必须由常量表达式初始化:”。所以这样做很好。
  2. 标记B-->错误消息暗示constexpr没有将变量xf隐式“const”。因此xf为int&。这与标记A矛盾。为什么?
  3. 标签C-->这是对const的通常引用
  4. 标记D-->额外添加“const”使其成为const引用,因为它在标记B中的行为。

“引用到const”和“const引用”这个词有区别吗?
似乎“引用到const”意味着引用正在引用const对象,同时不允许进行修改,而“const引用”是指引用是const但可以指向const或非const对象。

这是一件非常令人困惑的事情。

2个回答

0
“reference to a const”和“const reference”这两个词有区别吗?
概念上是有区别的,但“const reference”在逻辑上折叠成了“reference”,因为从技术上讲,所有引用都是常量。这也是为什么语言不允许您将引用声明为显式的“const”的原因。尽管如此,在语言中仍然存在一些情况,可以谈论“const reference”。请考虑以下示例:
typedef int &intref;

int main() {
    int x = 0;
    const intref xf = x;
    return 0;
}

在这种情况下,xf 实际上是一个 const 引用(而不是引用到 const),并且声明仍然有效。这将导致警告忽略 const 限定符,但它仍然可以编译和运行。这说明为什么仍然非常重要严格遵守声明顺序规则。
理解此声明的下一个非常重要的信息是应用 constexpr 关键字以及当我们说它“意味着 const”时确切含义。 constexpr 关键字始终指的是声明中的对象(而不是类型),因此当我们说 constexpr 意味着 const 时,它在手摆动的意义上表示,您可以省略 constexpr 声明的最内层部分(例如此示例中的 xf)上的 const 关键字,因为它是多余的。在引用的特殊情况下,它不仅是多余的,而且不允许使用。您可以认为编译器抛出错误有点不必要,因为您可以通过 typedef 来解决它,但原则仍然适用,缺少 const 的应用规则也适用。
将所有这些放在一起,在您的例子中,您可以将声明B大声读出来,例如:
"xf是一个constexpr,它是一个引用(根据定义是const,因此不需要暗示const)指向一个整数。"
但是我们有一个问题,就是我们试图声明一个对非常量对象的引用并将其分配给常量对象。这正是编译器抱怨的地方。
另请参见this

您提到的const的定义是指引用不允许指向不同的对象。我明白了。我看到了constexpr int &xf = x;const int &x;没有什么不同。这里的const表示引用不允许修改所指对象,因为后者是const。我只是不明白为什么constexpr int &xf = x;不等同于const int &xf = x,因为根据《C++ Primer》的说法,constexpr隐含地意味着const。 - yapkm01
你提到了"But here we have a problem, in that we're trying to declare a reference to a non-constant object ..." --> 这是令人困惑的部分。我认为它应该是声明一个对常量的引用,因为constexpr int &xf = x .. 我认为它应该是const int &xf=x; 我认为我的困惑根源在于为什么constexpr int &xf不能转换为const int &xf; - yapkm01
这是一个非常微妙的问题,我理解造成困惑的原因。让我花点时间尝试重新表述一下答案,希望能有所帮助。我不确定这些注释块中是否能够提供足够的信息。 - Jon Reeves
我理解你使用的typedef示例。我也理解这部分内容:“xf是一个constexpr,它是一个引用(根据定义是const,因此不需要暗示const)到一个整数。” 因此,使用等效的读取constexpr int x = 1; (TAG A) .. 它将是“x是一个constexpr,它是一个int,并且它隐含(添加)了const。因此,这里的区别在于xf不需要添加const,因为它是多余的,但对于x则不然。你能确认我的评估是否正确吗?谢谢。 - yapkm01
没错,@yapkm01。另一种思考方式可能是:编译器查看xf,将“const”添加到它上面,但由于xf已经是引用的常量,所以不会发生任何特殊情况。此外,我不确定为什么这个问题被标记为重复。在我看来,它实际上似乎是一个稍微不同的问题。 - Jon Reeves
显示剩余2条评论

0

B 中的 constexpr 指的是变量 xf,而不是类型(int & constexpr xf;,虽然我不知道是否会编译)。变量 xf 是一个 constexpr,它的类型是 int &。这就是为什么试图将其绑定到 x 失败的原因。


谢谢,但我认为对于引用来说只有较低的const级别。指针可以有顶层和底层const,但引用不行。 - yapkm01
@yapkm01 我看到这有点混淆。我已经将其删除了。 - 1201ProgramAlarm
据我所知,constexpr 将隐式地向其添加 const 限定符。因此,它将是 const int &xf 而不是 int &xf。 - yapkm01
为什么 constexpr int x=1; 的类型是 const int 而不是 int?constexpr int x=1 明显改变了类型。这难道不与上面的解释相矛盾吗? - yapkm01

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接