Jam*_*lis 29 c++ arrays reference overload-resolution c++11
考虑以下程序:
#include <cstddef>
#include <cstdio>
void f(char const*&&) { std::puts("char const*&&"); } // (1)
void f(char const* const&) { std::puts("char const* const&"); } // (2)
template <std::size_t N>
void f(char const (&)[N]) { std::puts("char const(&)[N]"); } // (3)
int main()
{
const char data[] = "a";
f(data);
}
Run Code Online (Sandbox Code Playgroud)
哪个f应该叫?为什么?
三个编译器的最新发布版本不同意这个问题的答案:
在不同的C++ 0x草案中,重载决策规则是否发生了很大变化?或者,这两个编译器真的完全错了吗?哪个重载是根据最新的C++ 0x草案选择的正确重载?
Joh*_*itb 12
首先,所有三个的转换序列是相同的,除了对于前两个,存在左值变换(左值到左值转换),但是它不用于排序转换序列.这三个都是完全匹配(函数模板特化具有参数类型char const(&)[2]).
如果你重复规则13.3.3.2p3,你就停在这一段
S1和S2是引用绑定(8.5.3),并且都不引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将rvalue引用绑定到rvalue,S2绑定左值引用.
如果需要将左值引用绑定到左值,则无法形成转换序列,规范在13.3.3.1.4p3处说明.如果你看一下8.5.3p5最后一个子弹的引用绑定是如何工作的,它将从数组lvalue 创建一个临时的(我认为它们意味着rvalue临时)类型char const*,并将引用绑定到该临时.因此,我认为(1)比(2).同样适用于(1)反对(3),虽然我们不需要这个因为(3)是一个模板,所以在平局,我们会(1)再次选择.
在n3225,他们更改了引用绑定规则,以便rvalue引用可以绑定到lvalues的初始化表达式,只要引用将绑定到rvalue(可能通过在之前正确转换初始化程序而创建).这可能会影响Visual C++的处理,这可能不是最新的.
我不确定铿锵声.即使它会被忽略(1),那么它最终会在(2)和之间产生联系(3),并且需要选择,(2)因为它是非模板.
我认为8.5.3p5最后一颗子弹令人困惑,因为它说"其他类型是临时的......".目前尚不清楚临时是否被认为是左值或者是13.3.3.1.4p3的右值,这意味着我不确定以下内容应该如何根据规范的确切字样表现出来
void f(int &);
void f(int &&);
int main() {
int n = 0;
f(n);
}
Run Code Online (Sandbox Code Playgroud)
如果我们假设临时被第13条视为rvalue,那么我们将rvalue ref绑定到第二个函数中的rvalue和第一个函数中的左值.因此,我们将选择第二个函数,然后通过8.5.3p5最后一个子弹获得诊断,因为它T1与T2参考相关.如果我们假设临时被第13条视为左值,则以下内容将不起作用
void f(int &&);
int main() {
f(0);
}
Run Code Online (Sandbox Code Playgroud)
因为我们将rvalue ref绑定到左值,而第13条将使该函数不可行.如果我们解释"将一个rvalue ref绑定到一个左值"来引用初始化表达式而不是绑定到的最终表达式,我们将不接受以下内容
void f(float &&);
int main() {
int n = 0;
f(n);
}
Run Code Online (Sandbox Code Playgroud)
然而,这在n3225中有效.所以似乎有些混乱 - 我向委员会发送了一份关于此的DR.