簡體   English   中英

帶有SFINAE偽參數的模糊模板

[英]Ambiguous template with SFINAE dummy parameter

考慮一種情況,其中需要在另一個模板的虛擬參數內使用另一個模板g (例如,可能是某些enable_if表達式)驗證類型T ,如下所示:

template<class>        struct g { typedef void type; };
template<class, class> struct f {};
template<class T>      struct f<T, void> {};                  // Case A
template<class T>      struct f<T*, typename g<T>::type> {};  // Case B

int main() { f<int*, void> test; }

在這里,為了簡單起見, g並沒有真正做任何事情。 案例B中的第二個參數位於非弱化上下文中,因此直觀地認為案例B案例A更專業。 可悲的是,gcc和clang都會抱怨模板在上面的實例化中是模棱兩可的。

如果要刪除虛擬參數,那么它編譯就好了。 如何添加一個非參數參數會以某種方式破壞T*T更專業的合理期望?

這是使用替換算法的快速檢查:

   f<Q , void      >
-> f<T*, g<Q>::type> // [failed]

   f<Q*, g<Q>::type>
-> f<T , void      > // [to fail or not to fail?]
// One would assume that 2nd parameter is ignored, but guess not?

當出現歧義時,使用模板的部分排序來解決它。 但是, 任何替換發生之前 ,這些部分排序是在模板上建立的,而不是在執行了 (部分或完全)替換之后 - 這是你期望通過在typename g<T>::type替換T int typename g<T>::type ,產生typename g<int>::type ,因此(由於g的定義) void

第14.8.2.4/2段規定了如何建立部分排序( 關於以下段落的更詳細討論,請參見SO上的答案 ):

兩組類型用於確定部分排序。 對於涉及的每個模板,都有原始函數類型和轉換后的函數類型。 [注意:轉換類型的創建在14.5.6.2中描述。 -end note]演繹過程使用變換后的類型作為參數模板,將另一個模板的原始類型作為參數模板。 對於部分排序比較中涉及的每種類型,此過程完成兩次:一次使用轉換的模板-1作為參數模板,使用template-2作為參數模板,再次使用轉換的模板-2作為參數模板和模板-1作為參數模板。

在任何替換之前,在不知道T將假設什么值的情況下,你無法告訴(並且編譯器都不能告訴) 案例B是否比案例A更專業或更不專業。 因此,這兩個專業都不比另一個更專業。

換句話說,問題不在於這個部分專業化:

template<class T> struct f<T, void>; // Case A

比這個更專業(通過部分替換獲得):

template<class T> struct f<T*, void>; // Case B

如果這就是你所擁有的,那么答案顯然是案例B更專業。 相反,問題是對於任何可能的T ,這個專業化:

template<class T> struct f<T, void>; // Case A

比這更專業:

template<class T> struct f<T*, typename g<T>::type>; // Case B

由於無法為任何T建立,因此案例B既不比案例A更專業也更不專業,並且當兩者都可行時,您會產生歧義。

如果您想知道部分排序是否考慮了非推導上下文中的參數,則在第14.8.2.4/11段的注釋中提到:

在大多數情況下,所有模板參數必須具有值以便推斷成功,但是對於部分排序目的,模板參數可以保持不帶值,前提是它不用於用於部分排序的類型。 [ 注意:使用非推斷上下文中使用的模板參數。 - 尾注 ]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM