为什么rvalue不能赋值给constexpr引用变量

3
我有以下代码
constexpr int into(int a,int b)
{
  int c=a*b;
  return c;
}

int main()
{
 constexpr int &n=into(5,5);

}

我阅读了MSDN的资料,constexpr这个关键字是在C++11中引入的,在C++14中得到了改进。它表示常量表达式。与const类似,可以应用于变量,以便在任何代码尝试修改该值时引发编译器错误。

在我阅读完之后,我认为constexpr可以取代const,但在上述代码中,我却得到了一个编译器错误:

`int main()':
invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'`
当将 constexpr 替换为 const 时,它可以正常工作。我不理解这种行为;有人可以解释一下吗?

1
constexpr 引用必须绑定到全局变量。请参见此处的答案。 - wally
@flatmouse,感谢您的回复...链接中的一个答案说:“引用在概念上等同于取变量的地址,而局部变量的地址不是常量”。当我使用const时,它会绑定。但不仅限于constexpr。我相信const和constexpr对变量的行为是相同的。 - RaGa__M
问题可能是into的返回值没有被保存在任何地方,但是您确实保存了对该返回值的引用,那么这个引用必须指向哪里呢? - Oebele
需要保存吗?函数调用暂时没有保存结果,编译器的RVO是否发挥作用? - RaGa__M
2个回答

6

constexpr关键字与const不同,它直接应用于引用类型变量int&,但没有任何效果。

typedef int &int_ref;

int main() {
    int x = 1;
    int &a = x;          // OK
    int_ref b = x;       // OK, int_ref is 'int &'
    const int &c = 1;    // OK, reference to const int
    const int_ref d = 1; // error: type of d is 'int &'
                         // qualifier on reference are being ignored
}

constexpr int &nconstexpr int_ref n 是相同的,而 const int &nconst int_ref n 的限定符不同。


3

被标记为constexpr的表达式将在编译时解析,这将把into(5,5)的结果视为int字面量。我们知道,在C++中不能将引用绑定到int字面量。

您可以通过在全局范围内创建constexpr int x=into(5,5);,并在主函数内创建一个constexpr const int引用来使其工作,强制x在调用main之前被解析,从而允许将引用绑定到x

constexpr int into(int a,int b) {
  int c=a*b;
  return c;
}

// guaranteed to be resolved before main is called
constexpr int x = into(5,5);

int main() {
 constexpr const int& n = x;
 static_assert(n == 25, "whoops!");
}

要直接回答你的问题,这与rvalue或移动语义完全无关,而是constexpr的微妙之处。
如果全局作用域让您感到不适,您也可以将x设置为static,并在引用绑定之前进行初始化,这对我来说似乎更自然:
constexpr int into(int a,int b) {
  int c=a*b;
  return c;
}  

int main() {
 // guaranteed to be resolved before main is called
 static constexpr int x = into(5,5);
 constexpr const int& n = x;
 static_assert(n == 25, "whoops!");
}

1
“正如我们所知,C++中的引用不能绑定到int字面值。” 您指的是哪些引用? - Piotr Skotnicki
1
@erip,你说的“into(5,5)作为int字面值不清楚。我们知道,在C++中,引用不能绑定到int字面值。”我相信调用into()函数会返回int&&,它是一个rvalue,应该分配给常量引用。当我把const int &n = into(5,5)放在main里时,一切都很顺利。如果const可以,为什么constexpr不能?难道constexpr缺少处理这种情况的东西吗? - RaGa__M
1
根据您的推理,应该可以编写“constexpr const int&”。 - Piotr Skotnicki
@PiotrSkotnicki,仍然存在解析时间的问题。static constexpr const int& n = into(5,5);是完全合法的,因为它保证在调用main时已经解析完成。 - erip
1
@RichardGeorge 澄清:您的假设是错误的,constconstexpr 是不同的。constexpr 的意思是“在编译时已知”,而 const 的意思是“无法在每次迭代分配后更改”。const int i& = n; 将 i 分配给本轮的任何 n,但我们不能通过 i 进行修改。constexpr i = 25 意味着 i 可以在编译期间被省略,并且可以用 25 替换它。 - kfsone
显示剩余4条评论

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