33

§3.10 第 9 节说“非类右值总是有 cv 非限定类型”。这让我想知道...

int foo()
{
    return 5;
}

const int bar()
{
    return 5;
}

void pass_int(int&& i)
{
    std::cout << "rvalue\n";
}

void pass_int(const int&& i)
{
    std::cout << "const rvalue\n";
}

int main()
{
    pass_int(foo()); // prints "rvalue"
    pass_int(bar()); // prints "const rvalue"
}

根据标准,非类类型没有 const rvalue 这样的东西,但bar()更喜欢绑定到const int&&. 这是编译器错误吗?

编辑:显然,this也是一个 const rvalue :)

编辑:这个问题似乎在 g++ 4.5.0 中得到修复,现在两行都打印“rvalue”。

4

2 回答 2

11

委员会似乎已经意识到标准的这一部分存在问题。CWG 第 690 期讨论了与标准完全相同的部分(在 2009 年 9 月的“附加说明”中)的一个有点相似的问题。我猜很快就会为标准的这一部分起草新的语言。

编辑:我刚刚在 comp.std.c++ 上提交了一篇文章,指出了问题并为标准的相关部分提出了新的措辞。不幸的是,作为一个有节制的新闻组,当它通过那里的批准队列时,几乎每个人都可能已经忘记了这个问题。

于 2010-01-31T00:27:22.043 回答
2

好点子。我想有两件事要看:1)正如你指出的非类右值事物和 2)重载解析是如何工作的:

最佳函数的选择标准是参数的数量、参数与候选函数的参数类型列表的匹配程度、[...]

我没有在标准中看到任何告诉我非类右值在重载解析期间被特殊处理的内容。

您的问题已包含在我拥有的标准草案(N-4411)中:

然而,真正起作用的是对引用绑定、隐式转换序列、引用和重载解析的并行阅读:

13.3.3.1.4 引用绑定

2 当引用类型的参数不直接绑定到参数表达式时,转换顺序是根据 13.3.3.1 将参数表达式转换为引用的基础类型所需的顺序。

13.3.3.2 对隐式转换序列进行排序

3 两个相同形式的隐式转换序列是不可区分的转换序列,除非以下规则之一适用:

— 标准转换序列 S1 是比标准
转换序列 S2 更好的转换序列,如果

— S1 和 S2 是引用绑定 (8.5.3),两者都没有引用非静态成员函数的隐式对象参数,声明时没有引用限定符,并且 S1 将左值引用绑定到左值,S2 绑定右值引用或 S1将右值引用绑定到右值,S2 绑定左值引用。

[ 例子:

int i;
int f();
int g(const int&);
int g(const int&&);
int j = g(i); // calls g(const int&)
int k = g(f()); // calls g(const int&&)
于 2010-01-31T00:16:24.547 回答