2017-09-03 125 views
3
// g++(5.4) 

void func(int * const &) {} 
void func(int *) {} 

template <typename T> void tfunc(const T &) {} 
template <typename T> void tfunc(T *) {} 

int main() 
{ 
    int a = 0; 

    func(&a); // ambiguous 
    tfunc(&a); // unambiguous 

    return 0; 
} 

根据我的另一个测试,tfunc(&a)实例第一模板void tfunc(int * const &)具有相同的参数类型作为第一个非模板。超载模板分辨率

那么,为什么第一个电话含糊不清,但第二个电话不是?

+0

对于第一呼叫的发挥机制是参数通常值转换为普通函数重载解析。两种(非)转换显然同样好。对于第二次调用,正在进行的机制是函数模板参数推导。这里赢了,因为它是*完全匹配*。对不起,我不能给你一个完整的答案,直到详细程度,但这是寻找答案的方向:游戏中的机制是非常不同的,具有不同的规则集。 –

回答

5

在其他方面同样好给定两个函数模板,重载方案将选择更加专业化函数模板,使用俗称部分排序的过程。确切的规则相当复杂,但本质上它试图确定参数模板A的集合是否可以被调用是参数集合B的一个(适当的)子集可以被调用。如果是的话,则A比B更专业化,并且重载分辨率将优选A.

因此,在你的情况下,tfunc(const T&)可以用〜everything调用;只能用指针调用tfunc(T*)。后者更专业化,因此被选中。

如果您对标准和详细规则感兴趣,请参阅[temp.func.order][temp.deduct.partial]

+0

OP声称调用* first *模板,这与您的答案不一致(对我来说令人惊讶)。这个索赔中的OP是否不正确?我读过OP是否错误?或者有什么奇怪的事情发生? – Yakk

+0

@Yakk:是的,OP的说法是错误的。 (我没有注意到我在这个问题上的原始评论。) –

+0

@Yakk我不认为它声称第一个*被*称为;它声称第一个*可以被称为 - 或者是可行的 - 通过推导'T = int *'(“另一个测试”)。 –

2

有重载决策模板功能的一些特殊的规则,其中之一是:

F1和F2功能模板特,和F1的功能模板的模板,更专业的F2根据14.5.6.2中描述的偏序排列规则。

请参阅this question关于如何确定哪个函数模板更专用。

在这里,作为第二个模板函数更专业化,没有歧义。


#include <iostream> 
void func(int * const &) {} 
void func(int *) {} 

template <typename T> void tfunc(const T &) {std::cout << "#1\n";} 
template <typename T>void tfunc(T *) {std::cout << "#2\n";} 

int main() 
{ 
    int a = 0; 

    //func(&a); // ambiguous 
    tfunc(&a); // unambiguous 

    return 0; 
} 
// output: #2 

编辑:尽管在https://ideone.com/C9rF8b测试,我们可以看到第二个模板选择,而不是在问题规定的第一个。

0

因为const指针和非const指针(即T * constT *)如果它们出现在函数的参数中并没有区别,所以传递值(通过复制)并通过const引用传递。这就是为什么f(&a)含糊不清的原因。

对于第二个,因为&a已解析为int *,所以第二个模板匹配得更好,因为它更专业化(它不能接受非指针参数)。第一个模板更一般,所以没有使用。

如果你改变了第一个模板功能,这也将是模棱两可:

template <typename T> 
void tfunc(T * const &) {}