这种模板函数重载的情况我无法理解
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;
}
我预计bar<int>(5)
至少会导致歧义。这里涉及到模板函数重载解析的什么疯狂规则?
一旦我们得到候选函数集(两个bar
s),然后将其缩减为可行函数(仍然两个bar
s),我们必须确定最佳可行函数。如果有多于一个,我们得到一个歧义错误。我们确定最佳人选的步骤见[over.match.best]:
如果对于所有参数i, ICSi(F1)不是比ICSi(F2)更差的转换序列,那么[A]可行函数F1被定义为比另一个可行函数F2更好的函数,然后
-对于某些参数j, ICSj(F1)是比ICSj(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"那么专业。
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 函数中堆分配的效果与缺少堆分配的情况
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 在这种情况下,java对象是否可以调用本机函数
- 这个c++代码是如何在没有定义函数的情况下运行的
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- 如何在没有函数的情况下编写此代码并使C++更简单?
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- A类的定义需要B类的定义,如何在不公开B的定义的情况下公开A的公共函数?
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 有没有办法在不使用 #ifdef 的情况下不编译发布版本中的单元测试函数体?
- C++ strcpy 函数在少数主要情况下失败
- C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 如何在没有复制构造函数的情况下为地图设置值?
- 在这种情况下,如何传递成员函数而不是函数?
- 上情况函数C