重载模板分辨率

时间:2017-09-03 01:35:25

标签: c++ templates overloading

// 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 &),其参数类型与第一个非模板相同。

那么,为什么第一个调用不明确但第二个不是?

3 个答案:

答案 0 :(得分:5)

鉴于两个功能模板同样如此好,过载分辨率将使用通常称为部分排序的过程选择更专业的功能模板。确切的规则非常复杂,但实际上它试图确定是否可以调用参数模板A的集合是参数集的(适当的)子集,模板B可以被调用。如果是这样,则A比B更专业,并且重载决策将更喜欢A。

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

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

答案 1 :(得分:2)

模板函数的重载解析有一些特殊规则,其中之一是:

  

F1和F2是功能模板专精,根据14.5.6.2中描述的部分排序规则,F1的功能模板比F2的模板更专业。

请参阅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进行了测试,但我们可以看到第二个模板被选中,而不是问题中所述的第一个模板。

答案 2 :(得分:0)

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

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

如果将第一个模板函数更改为此函数,它也将是不明确的:

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