在获取地址的上下文中,哪个是最专业的函数模板?

Which is the most specialized function template in the context of taking the address?

考虑这个example

#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.deduct.funcaddr#1],这两个函数模板在#3中都是可行的。因此,[over.over#5]需要在这里申请

Any given function template specialization F1 is eliminated if the set contains a second function template specialization whose function template is more specialized than the function template of F1 according to the partial ordering rules of [temp.func.order].

判断#1#2哪个更专业,[temp.deduct.partial#3.3]适用于

The types used to determine the ordering depend on the context in which the partial ordering is done:

  • [...]
  • In other contexts the function template's function type is used.

因此,参与偏序的P和A应该分别是那两个函数模板的函数类型。取#2函数类型为P,#1函数类型为A,AP成功[temp.deduct.type#10]

If P and A are function types that originated from deduction when taking the address of a function template ([temp.deduct.funcaddr]) or when deducing template arguments from a function declaration ([temp.deduct.decl]) and Pi and Ai are parameters of the top-level parameter-type-list of P and A, respectively, Pi is adjusted if it is a forwarding reference ([temp.deduct.call]) and Ai is an lvalue reference, in which case the type of Pi is changed to be the template parameter type (i.e., T&& is changed to simply T).

相反,由于我们无法从 T&& 推导出 T&,因此 #1 处的函数模板比​​ #2 处的函数模板更专业。因此,#2 的特化应该从集合中删除。最终,该集合仅包含 #1 的一个特化。这里应该是不含糊的。为什么GCC和Clang都说取地址不明确?

根据您自己的分析,GCC 和 Clang 在重载决策中的屈服和歧义是错误的。

这可以说与 CWG 1164, albeit not being in the context of a function call 有关,其意图可以说与 CWG 1164 [强调 我的函数调用的情况相似]:

1164. Partial ordering of f(T&) and f(T&&)

Section: 13.10.3.2 [temp.deduct.call] Status: C++11 Submitter: US Date: 2010-08-03

[Voted into the WP at the November, 2010 meeting.]

N3092 comment US 77 The following example is ambiguous:

template<typename T> int f(T&);
template<typename T> int f(T&&);
int i;
int j = f(i);

Because of the special deduction rule for lvalues passed to rvalue-reference parameters, deduction produces f(int&) for both templates, and they are indistinguishable.

Because f(T&) accepts a strict subset of the things that f(T&&) does, it should be considered more specialized by the partial ordering rules.

Proposed resolution (August, 2010): [...]

您自己的分析得出了一个与 CWG 1164 一致的过载结果,但对于另一个上下文,它从未在 CWG 1164 中解除并且(可以说)不太常见。


我们可能会注意到 GCC 和 Clangs 都将 CWG 1164 的决议标记为 ?/Unknown:
- GCC: C++ Defect Report Support in GCC
- C++ Defect Report Support in Clang
所以它可能只是部分实施(OP 的示例比 CWG 1164 的示例更多的是角落用例)。