简体   繁体   English

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

[英]This case of template function overloading eludes my understanding

#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;
}

I expected bar<int>(5) to result in an ambiguity, at the very least. 我预计bar<int>(5)至少会产生歧义。 What crazy rule about template function overload resolution is involved here? 这里涉及到关于模板函数重载决策的疯狂规则?

Once we get our candidate functions set (both bar s), and then whittle it down to the viable functions (still both bar s) we have to determine the best viable function. 一旦我们设置了候选函数(两个bar ),然后将其缩小到可行的函数(仍然是两个bar ),我们必须确定最佳的可行函数。 If there is more than one, we get an ambiguity error. 如果有多个,我们会出现歧义错误。 The steps we take to determine the best one are laid out in [over.match.best]: 我们采取的确定最佳步骤的步骤在[over.match.best]中列出:

[A] viable function F1 is defined to be a better function than another viable function F2 if for all arguments i , ICS i (F1) is not a worse conversion sequence than ICS i (F2), and then [A]可行函数F1被定义为比另一个可行函数F2更好的函数,如果对于所有自变量i ,ICS i (F1)不是比ICS i (F2)更差的转换序列,然后
— for some argument j , ICS j (F1) is a better conversion sequence than ICS j (F2), or, if not that, - 对于某些参数j ,ICS j (F1)是比ICS j (F2)更好的转换序列,或者,如果不是,

Both functions take an argument of type int , so both conversion sequences are identical. 两个函数都采用int类型的参数,因此两个转换序列都是相同的。 We continue. 我们继续。

— the context is an initialization by user-defined conversion [...] - 上下文是用户定义的转换初始化[...]

Does not apply. 不适用。

— the context is an initialization by conversion function for direct reference binding (13.3.1.6) of a reference to function type, [...] - 上下文是转换函数的初始化,用于对函数类型的引用的直接引用绑定(13.3.1.6),[...]

Does not apply. 不适用。

— F1 is not a function template specialization and F2 is a function template specialization, or, if not that, - F1不是函数模板特化,F2是函数模板特化,或者,如果不是,

Both bar<int> s are function template specializations. bar<int>都是函数模板特化。 So we move onto the very last bullet point to to determine the best viable function. 因此,我们进入最后一个要点,以确定最佳可行功能。

— F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2. - F1和F2是功能模板特化,根据14.5.6.2中描述的偏序规则,F1的功能模板比F2的模板更专业。

The partial ordering rules basically boil down to us synthesizing new unique types for the arguments of both bar overloads and performing template deduction on the other overload. 部分排序规则基本上归结为我们为bar重载和在另一个重载上执行模板推导的参数合成新的唯一类型。

Consider the "b" overload first. 首先考虑“b”过载。 Synthesize a type typename identity<Unique1>::type and attempt to perform template deduction against T . 合成类型typename identity<Unique1>::type并尝试对T执行模板推导。 That succeeds. 这成功了。 Simplest cast of template deduction there is. 最简单的模板演绎有。

Next, consider the "a" overload. 接下来,考虑“a”过载。 Synthesize a type Unique2 and attempt to perform template deduction against typename identity<T>::type . 合成类型Unique2并尝试对typename identity<T>::type执行模板推导。 This fails ! 失败了 This is a non-deduced context - no deduction can succeed. 这是一个非推断的上下文 - 没有扣除可以成功。

Since template type deduction only succeeds in a single direction, the bar(typename identity<T>::type) overload is considered more specialized, and is chosen as the best viable candidate. 由于模板类型推导仅在单个方向上成功,因此bar(typename identity<T>::type)重载被认为更加专业化,并被选为最佳可行候选者。


bogdan presents another interesting case for looking at partial ordering. bogdan提出了另一个有趣的案例来看待部分排序。 Consider instead comparing: 请考虑比较:

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);

Again, both candidates are viable (this time even without explicitly specifying T ) so we look at the partial ordering rule. 同样,两个候选者都是可行的(这次甚至没有明确指定T )所以我们看看部分排序规则。

For the "c" overload, we synthesize arguments of type UniqueC, UniqueC and attempt to perform deduction against T, typename identity<T>::type . 对于“c”重载,我们合成了UniqueC, UniqueC类型的UniqueC, UniqueC并尝试对T, typename identity<T>::type进行推导。 This succeeds (with T == UniqueC ). 这成功了( T == UniqueC )。 So "c" is at least as specialized as "d". 所以“c”至少与“d”一样专业。

For the "d" overload, we synthesize arguments of type UniqueD, typename identity<UniqueD>::type and attempt to perform deduction against T, T . 对于“d”重载,我们合成类型为UniqueD, typename identity<UniqueD>::type参数UniqueD, typename identity<UniqueD>::type并尝试对T, T执行推导。 This fails! 这失败了! The arguments are of different types! 参数是不同类型的! So "d" is not at least as specialized as "c". 所以“d”至少不如“c”那么专业。

Thus, the "c" overload is called. 因此,调用“c”重载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM