#include <iostream>
#define FUNC() { std::cout << __PRETTY_FUNCTION__ << "n"; }
void foo(char const*&& ) FUNC() // A
void foo(char const(&)[4]) FUNC() // B
int main()
{
foo("bar");
}
演示
当在第一个过载(A(的参数类型中使用右值引用时,clang当前主机明确地选择过载A而不是B。另一方面,GCC当前主机抱怨模糊。
我非常惊讶的是,字符串literal是4char const
的左值([expr.prim.literal]/1,[lex.string]/6(应该更喜欢重载A上的数组到指针转换,而不是重载B上的标识转换。
如果没有右值引用(即void foo(char const*)
(,GCC和clang都会以不明确为由拒绝调用。这也是我不完全理解的,因为我猜仍然存在数组到指针的转换,因此[over.ics.rank]p3.2.1适用:
如果,标准转换序列S1是比标准转换序列S2更好的转换序列
- (3.2.1(S1是S2的适当子序列(比较[over.ics.scs]定义的规范形式的转换序列,不包括任何Lvalue转换;身份转换序列为被认为是任何非恒等式转换的子序列序列(或者如果不是
这两种情况下发生了什么?
(这只是部分答案,涵盖第二种情况(
这两种情况都发生了什么?
关于第二种情况,关于为什么以下重载
void foo(char const* ) FUNC() // A
void foo(char const(&)[4]) FUNC() // B
产生不明确的过载(对于Clang和GCC(;[over.ics.rank]/3.2.1可能倾向于B,这是一种身份转换,而不是A,需要数组到指针的转换,这反过来又属于Lvalue Transformation的转换类别:
如果,标准转换序列S1是比标准转换序列S2更好的转换序列
- (3.2.1(S1是S2的适当子序列(比较[over.ics.scs]定义的正则形式的转换序列,排除任何Lvalue变换;单位转换序列被认为是任何非单位转换序列的子序列(,或者,如果不是
- […]
然而,正如我对上面第一个强调的段的解释一样,当应用[over.ics.rank]/3.2.1时,Lvalue Transformation:s被从序列S1和S2中排除,并且第二个强调的段只有在应用了该排除之后才适用。
正如@LanguageLawyer在一条评论中指出的那样,CWG 1789强调了规则确实允许这种模糊性,自2013年以来,该规则没有任何进展或反馈。
1789.过载分辨率下的数组引用与数组衰减
- 章节:12.4.4.3[over.ics.rank]
- 状态:起草
- 提交人:费萨尔·瓦利
- 日期:2013-10-01
当前的规则是一个类似的例子
template<class T, size_t N> void foo(T (&)[N]); template<class T> void foo(T *t); int arr[3]{1, 2, 3}; foo(arr);
模棱两可,即使第一个是身份匹配,第二个需要进行左值转换。这是可取的吗?