#include <iostream>
using namespace std;
void f(const char * const &s) {
cout << "lvalue" << endl;
}
void f(const char * const &&s) {
cout << "rvalue" << endl;
}
int main()
{
char s[] = "abc";
f("abc");
f(s);
}
输出:
rvalue
rvalue
为什么输出不是“rvalue lvalue”?
答案 0 :(得分:3)
字符串文字和s
都不是指针(它们是数组),所以标准的相关部分是[conv.array]:
类型为“
N
T
数组”或“T
未知范围数组”的左值或右值可以转换为到prvalue类型“指针”T
“。结果是指向数组第一个元素的指针。
请注意
char const *p = s;
f(p);
打印“左值”,以显示它的效果与预期的指针一样。
补遗:评论:在
的情况下char *p = s;
f(p);
如果rvalue重载存在但打印“rvalue”但如果删除则不会导致编译器错误,标准的另外两个部分会起作用 - 其中一个部分似乎禁止char*
的绑定完全放到char const *const &
,另一个放回窗口。
第一个是[dcl.init.ref] / 4,其中声明
指定类型“ cv1
T1
”和“ cv2T2
”,“ cv1 {{1}如果T1
与T2
的类型相同,或者{{1},则“与参考相关的与” cv2T1
“ }是T2
的基类。 “ cv1T1
”参考兼容与“ cv2T2
”如果T1
为< em>与参考相关的与T2
和 cv1 具有相同的cv资格,或者比 cv2 更高的cv资格。 (...)
它详细介绍了参考初始化的精确规则,所有这些都是相关的,但不幸的是,对于SO答案来说太长了。简而言之,对于 cv1 T1
的引用可以使用 cv2 T2
的对象初始化,如果这两个引用兼容的话
这个Legalese对我们的案例意味着T1
和T2
不是参考兼容(尽管char*
和char const *
会是),因为char*
不是char *const
,也不是另一个的基类。如果您考虑以下非法合法的代码,则此限制是有意义的:
char*
这是从[conv.qual] / 4中的类似示例改编而来的,它使用指向指针的指针来演示同样的问题。
[conv.qual]也是打开窗口的另一个相关部分。它在[conv.qual] / 1中说:
“指向 cv1
char const *
的指针”的prvalue可以转换为“指向 cv2const char c = 'c'; char *pc; const char*& pcc = pc; // #1: not allowed pcc = &c; *pc = 'C'; // #2: modifies a const object
的指针”的prvalue“ “ cv2T
”比“ cv1T
更符合资格”
由此可以得出T
可以转换为T
1 (与char*
引用兼容),这就是代码的原因如果删除char const *
的右值超载,仍会编译。但是,此转换的结果是prvalue,因此如果存在,则在重载分辨率中首选rvalue重载。
1 char const *const
glvalue - &gt; f
prvalue([conv.lval]) - &gt; char*
prvalue)
答案 1 :(得分:1)
s
是一个数组左值(所以"abc"
也就是这样 - 字符串文字是左值)。为了获得指针,执行数组到指针的转换。此转换产生一个指针prvalue,它优先绑定到右值引用过载。