考虑这个例子
#include <iostream>
template<class T>
void fun(T&){ //#1
std::cout<<"selected\n";
}
template<class T>
void fun(T&&){} //#2
int main() {
void(*ptr)(int&) = &fun; //#3
}
GCC和Clang都报告了一个错误,诊断结果“不明确”。根据[temp. dept.funcaddr#1],这样两个函数模板在#3
中都是可行的。因此,[over.over#5]需要在这里应用
如果集合包含第二个函数模板专门化,其函数模板比F1的函数模板更专门,则根据[temp. func.order]的部分排序规则消除任何给定的函数模板专门化F1。
要判断#1
和#2
之间哪个更专业,[temt. dept.部分#3.3]适用于它们
用于确定排序的类型取决于完成部分排序的上下文:
因此,用于参与部分排序的P和A应该分别是这两个函数模板的函数类型。将#2
的函数类型作为P,将#1
的函数类型作为A。根据[temt. dept.type#10],从A
中推断出P
是成功的
如果P和A是在获取函数模板的地址([temt. det.funaddr])或从函数声明([temt.det.decl])中推导模板参数时源自推导的函数类型,并且Pi和Ai分别是P和A的顶级参数类型列表的参数,如果Pi是转发引用([temp.deduct.call])并且Ai是左值引用,则Pi的类型被调整为模板参数类型(即T
相反,由于我们无法推导T
根据您自己的分析,GCC和Clang在过载分辨率中的屈服和歧义是错误的。
这可以说是与CWG 1164有关,尽管不是在函数调用的上下文中,但其意图应该可以说是类似于CWG 1164[强调我的]的函数调用的情况:
科:13.10.3.2[temp.deduct.call]状态:C 11提交者:US日期:2010-08-03
[在2010年11月会议上被选入WP。]
N3092注释US77以下示例含糊不清:
template<typename T> int f(T&);
template<typename T> int f(T&&);
int i;
int j = f(i);
由于传递给右值参数的左值的特殊演绎规则,演绎产生f(int
因为f(T
拟议决议(2010年8月):[…]
您自己的分析得到了与CWG 1164一致的重载结果,但对于另一个上下文,这在CWG 1164中从未取消,并且(可以说)不太常见。
我们可以注意到,GCC和Clangs都将CWG 1164的分辨率标记为?
/未知
:
-GCC:GCC中的C缺陷报告支持
-Clang中的C缺陷报告支持
所以它可能只被部分实现了(OP的示例比CWG 1164的示例更像是一个角落用例)。