考虑以下示例
#include <iostream>
template<class T>
void fun(T&){ //#1
std::cout<<"selectedn";
}
template<class T>
void fun(T&&){} //#2
int main() {
void(*ptr)(int&) = &fun; //#3
}
GCC和Clang都报告了诊断"含糊不清"的错误。根据[temp. deduction .funcaddr#1],这两个函数模板在#3
中都是可行的。因此,[结束。> #5]需要在这里应用
如果该集合包含第二个函数模板专门化,且该函数模板根据[temp. function .order]的偏序规则比F1的函数模板专门化程度更高,则消除给定的函数模板专门化F1。
为了判断#1
和#2
哪个更专门化,[temp. deduction .partial#3.3]适用于它们
因此,p和A用于参与偏排序应该分别是这两个函数模板的函数类型。设用于确定排序的类型取决于进行部分排序的上下文:
- […]
- 在其他上下文中,函数模板的函数类型使用。
#2
的函数类型为P,#1
的函数类型为a。根据[temp. deduction .type#10],从A
推导出P
成功。如果p和函数类型,起源于扣除当把一个函数模板的地址([temp.deduct.funcaddr])或当推断模板参数的函数声明([temp.deduct.decl])和π和Ai的顶级parameter-type-list参数p和,分别调整Pi如果是转发参考([temp.deduct.call])和人工智能是一个左值引用,在这种情况下,π的类型是改变模板参数类型(例如,T&和;
相反,由于我们不能从T&&
推导出T&
,因此#1
的函数模板比#2
的函数模板更专门化。因此,#2
的专门化应该从集合中消除。最终,该集合只包含#1
的一个专门化。这里应该是明确的。为什么GCC和Clang说接收地址是模糊的?
GCC和Clang在重载解析中产生歧义是错误的,根据您自己的分析。
这可能与CWG 1164有关,尽管不是在函数调用的上下文中,但其意图应该与CWG 1164中函数调用的情况相似[强调]我:
1164。f(T&)和f(T&&)的偏序
章节:13.10.3.2 [temp. deduction .call]状态:c++ 11提交者:US日期:2010-08-03
[在2010年11月的会议上投票加入WP]
N3092注释US 77下面的例子有歧义:
template<typename T> int f(T&); template<typename T> int f(T&&); int i; int j = f(i);
由于传递给的左值的特殊扣除规则右值引用形参,演绎对两者都产生f(int&)模板,它们是无法区分的。
因为f(T&)接受f(T&&)所做的事情的严格子集,它应该被认为是更专门化的部分排序规则。
建议决议(August, 2010):[…]
您自己的分析达到了与CWG 1164一致的过载结果,但用于另一个上下文中,这在CWG 1164中从未解除,并且(可以说)不太常见。
我们可能会注意到GCC和Clangs都将CWG 1164的解决方案标记为?
/Unknown
:
- GCC: GCC
- Clang
支持c++缺陷报告所以可能它只是部分实现(OP的例子比CWG 1164更像是一个角落用例)。