c++ - 这种模板函数重载的案例让我无法理解

标签 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)至少会导致歧义。这里涉及到什么关于模板函数重载解析的疯狂规则?

最佳答案

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

[A] viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

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

— the context is an initialization by user-defined conversion [...]

不适用。

— the context is an initialization by conversion function for direct reference binding (13.3.1.6) of a reference to function type, [...]

不适用。

— F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

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

— 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.

部分排序规则基本上归结为我们为 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”重载。

关于c++ - 这种模板函数重载的案例让我无法理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31391172/

相关文章:

c++ - 如何创建一系列线程以按启动顺序执行任务?

c++ - 无法在 Eclipse 中解析符号 'cv'

c++ - 针对 C++ 类型测试 opencv mat 数据类型的最佳方法是什么?

c++ - 使用模板和虚函数的技巧

c++ - 使用 auto 重载模板函数的解析

c++ - 为什么在宏中使用明显无意义的 do-while 和 if-else 语句?

C++将SDL_renderer传递给一个类

jquery - 如何使用 jquery 模板动态访问一些 json 值

C++ 嵌套结构继承规则(访问 protected 成员)

Java LR 或 LL 解析