2016-08-16 55 views
6

C++標準14.8.2 $ 7說:替代在模板參數推演中如何工作?

取代在所有類型和表達了在函數類型並在模板參數聲明使用發生。這些表達式不僅包括常量表達式,例如出現在數組邊界或非類型模板參數中的常量表達式,還包括sizeof,decltype以及允許非常量表達式的其他上下文中的常規表達式(即非常量表達式)。替換按詞彙順序進行,並在遇到導致扣除失敗的條件時停止。 [注意:異常規範中的等價替換隻有在例外規範被實例化時才能完成,在這種情況下,如果替換導致無效類型或表達式,則程序不合格。 - 注完]

這裏的標準提供了一個例子:

template <class T> struct A { using X = typename T::X; }; 
template <class T> typename T::X f(typename A<T>::X); 
template <class T> void f(...) { } 
template <class T> auto g(typename A<T>::X) -> typename T::X; 
template <class T> void g(...) { } 

void h() { 
    f<int>(0); // OK, substituting return type causes deduction to fail 
    g<int>(0); // error, substituting parameter type instantiates A<int> 
} 

爲什麼叫g<int>(0)是錯誤的嗎?尾隨返回類型T::X是否導致替換失敗?模板功能fg之間有什麼區別?

回答

4

其要點是,首先,

詞彙順序的取代前進並且當使扣失敗的條件 遇到

其次,停止的A<int>的實例化定義會觸發一個硬錯誤,而不是一個替代失敗,因爲這會導致在緊鄰的上下文之外實例化一個格式不正確的構造typename T::X(與T == int)。 [temp.deduct]/8

只有無效的類型,並在 功能型的它的模板參數類型的直接背景和表達式可以導致 扣失敗。 [:取代的類型和 表達式的評估可導致副作用,例如類模板特和/或功能模板 特,隱含定義的函數的生成等 這樣的副作用的實例化 不在「緊急情況下」,並且可能導致程序不合格。 - 注完]

隨着所討論的模板,代入typename T::X在扣除失敗函數類型結果(即,SFINAE);代入typename A<T>::X會導致嚴重錯誤。由於替換按照詞彙順序進行,因爲template <class T> typename T::X f(typename A<T>::X);它首先替換爲typename T::X,導致扣除失敗,並且不會嘗試進一步替換。另一方面,對於template <class T> auto g(typename A<T>::X) -> typename T::X;,首先替換爲typename A<T>::X,這會導致嚴重錯誤。

+0

返回類型如何作爲函數簽名的一部分而不是參數? – Barry

+0

@Barry我認爲返回類型和參數都被認爲是函數簽名的一部分 – Carousel

+0

@Barry它們都是函數模板簽名的一部分,但我可能不應該在這裏使用「簽名」。 –