这种模板函数重载的情况使我无法理解

时间:2015-07-13 18:50:13

标签: c++ templates language-lawyer overload-resolution

#include <iostream>

template<typename T>
struct identity
{
    typedef T type;
};

template<typename T> void bar(T) { std::cout << "a" << std::endl; }
template<typename T> void bar(typename identity<T>::type) { std::cout << "b" << std::endl; }

int main ()
{
    bar(5); // prints "a" because of template deduction rules
    bar<int>(5); // prints "b" because of ...?

    return EXIT_SUCCESS;
}

我预计bar<int>(5)至少会产生歧义。这里涉及到关于模板函数重载决策的疯狂规则?

1 个答案:

答案 0 :(得分:17)

一旦我们设置了候选函数(两个bar s),然后将其缩小到可行函数(仍然是bar s),我们必须确定 best 可行的功能。如果有多个,我们会出现歧义错误。我们采取的确定最佳方法的步骤在[over.match.best]中列出:

  

[A]可行函数F1被定义为比其他可行函数F2更好的函数如果对于所有参数 i ,ICS i (F1)并不是更糟糕转换序列比ICS i (F2),然后是    - 对于某些参数 j ,ICS j (F1)是比ICS j (F2)更好的转换序列,或者,如果不是,

两个函数都采用int类型的参数,因此两个转换序列都是相同的。我们继续。

  

- 上下文是用户定义的转换初始化[...]

不适用。

  

- 上下文是转换函数的初始化,用于对函数类型的引用的直接引用绑定(13.3.1.6),[...]

不适用。

  

- F1不是功能模板专业化,F2是功能模板专业化,或者,如果不是,

两个bar<int>都是函数模板特化。因此,我们进入最后一个要点,以确定最佳可行功能。

  

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

部分排序规则基本上归结为我们为bar重载的参数合成新的唯一类型,并在另一个重载上执行模板推导。

首先考虑“b”过载。合成类型typename identity<Unique1>::type并尝试对T执行模板推导。这成功了。最简单的模板演绎有。

接下来,考虑“a”过载。合成类型Unique2并尝试对typename identity<T>::type执行模板推导。这个失败!这是一个非推断的上下文 - 没有扣除可以成功。

由于模板类型推导仅在单一方向上成功,因此bar(typename identity<T>::type)重载被认为更加专业化,并被选为最佳可行候选者。

bogdan提出了另一个有趣的案例,用于查看部分排序。请考虑比较:

template <typename T> void bar(T, T); // "c"
template <typename T> void bar(T, typename identity<T>::type ); // "d"

bar(5,5);
bar<int>(5, 5);

同样,两个候选人都是可行的(这次甚至没有明确指定T),所以我们看看部分排序规则。

对于“c”重载,我们合成类型为UniqueC, UniqueC的参数,并尝试对T, typename identity<T>::type进行推导。这成功(使用T == UniqueC)。所以“c”至少和“d”一样专业。

对于“d”重载,我们合成类型为UniqueD, typename identity<UniqueD>::type的参数,并尝试对T, T进行推导。这失败了!参数是不同类型的!所以“d”至少不如“c”那么专业。

因此,调用“c”重载。