[英]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
),然后將其縮小到可行的函數(仍然是兩個bar
),我們必須確定最佳的可行函數。 如果有多個,我們會出現歧義錯誤。 我們采取的確定最佳步驟的步驟在[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是功能模板特化,根據14.5.6.2中描述的偏序規則,F1的功能模板比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
類型的UniqueC, UniqueC
並嘗試對T, typename identity<T>::type
進行推導。 這成功了( T == UniqueC
)。 所以“c”至少與“d”一樣專業。
對於“d”重載,我們合成類型為UniqueD, typename identity<UniqueD>::type
參數UniqueD, typename identity<UniqueD>::type
並嘗試對T, T
執行推導。 這失敗了! 參數是不同類型的! 所以“d”至少不如“c”那么專業。
因此,調用“c”重載。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.