使用rvalue引用const char的重载解析*

时间:2015-02-23 18:05:11

标签: c++ c++11 lvalue rvalue

#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”?

2 个答案:

答案 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”和“ cv2 T2”,“ cv1 {{1}如果T1T2的类型相同,或者{{1},则“与参考相关的与” cv2 T1“ }是T2的基类。 “ cv1 T1参考兼容与“ cv2 T2”如果T1为< em>与参考相关的与T2 cv1 具有相同的cv资格,或者比 cv2 更高的cv资格。 (...)

它详细介绍了参考初始化的精确规则,所有这些都是相关的,但不幸的是,对于SO答案来说太长了。简而言之,对于 cv1 T1的引用可以使用 cv2 T2的对象初始化,如果这两个引用兼容的话

这个Legalese对我们的案例意味着T1T2不是参考兼容(尽管char*char const *会是),因为char*不是char *const,也不是另一个的基类。如果您考虑以下非法合法的代码,则此限制是有意义的:

char*

这是从[conv.qual] / 4中的类似示例改编而来的,它使用指向指针的指针来演示同样的问题。

[conv.qual]也是打开窗口的另一个相关部分。它在[conv.qual] / 1中说:

  

“指向 cv1 char const *的指针”的prvalue可以转换为“指向 cv2 const char c = 'c'; char *pc; const char*& pcc = pc; // #1: not allowed pcc = &c; *pc = 'C'; // #2: modifies a const object 的指针”的prvalue“ “ cv2 T”比“ cv1 T更符合资格”

由此可以得出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,它优先绑定到右值引用过载。