2017-02-23 52 views
43

類模板特優選涉及改寫成特化功能模板和確定哪個功能模板是通過對於函數模板的排序規則[temp.class.order]更專門其中用於採摘的規則。考慮這個例子,那麼:類模板特偏序和功能合成

#include <iostream> 

template <class T> struct voider { using type = void; }; 
template <class T> using void_t = typename voider<T>::type; 

template <class T, class U> struct A { }; 

template <class T> int foo(A<T, void_t<T>>) { return 1; } 
template <class T> int foo(A<T*, void>)  { return 2; } 

int main() { 
    std::cout << foo(A<int*, void>{}); 
} 

GCC和鐺打印2這裏。這對於前面的一些例子是有意義的 - 根據未推導的上下文(voidvoid_t<T>)的推斷被忽略,因此推導<T, void_t<T>>針對<X*, void>成功,但推導出<T*, void>針對<Y, void_t<Y>>在兩個參數中均失敗。精細。

現在考慮這一概括:

#include <iostream> 

template <class T> struct voider { using type = void; }; 
template <class T> using void_t = typename voider<T>::type; 

template <int I> struct int_ { static constexpr int value = I; }; 

template <class T, class U> struct A  : int_<0> { }; 
template <class T> struct A<T, void_t<T>> : int_<1> { }; 
template <class T> struct A<T*, void>  : int_<2> { }; 

int main() { 
    std::cout << A<int*, void>::value << '\n'; 
} 

兩個鐺和gcc報告這種專業化模棱兩可,12之間。但爲什麼?合成的功能模板不是不明確的。這兩種情況有什麼區別?

+1

尋呼@bogdan。 – Barry

+0

我不是專家,但我認爲這與專業兩個'void'和'void_t'做這[工作](http://ideone.com/91pVA5) 。預期 – xinaiz

+0

@BlackMoses這並不做任何偏序如果只有一個匹配的專業化,它只是挑 – Barry

回答

4

Clang正在兼容GCC-(並與現有代碼兼容,這取決於這兩種行爲)。

考慮[temp.deduct.type] P1

[...]試圖找到模板參數值(一個類型參數類型,非價值類型參數或模板參數的模板),這將使P在替換推導值(稱爲推導出的A)後與A兼容。

問題的癥結在於「兼容」意味着這裏。

當部分定購功能模板,鏘僅僅推導出在兩個方向上;如果演繹在一個方向上成功但不是另一個方向,則它假定這意味着結果將是「兼容的」,並將其用作排序結果。

當部分地有序類模板部分特例,但是,鏘解釋「相容的」爲表示「相同的」。因此,只有將一個部分專業化比另一個部分專業化更加專業化,如果將從其中一個部分推導出來的參數代入另一個部分專業化會再現原來的部分專業化。

更改這兩個中的任何一個以匹配另一個可打破大量實際代碼。 :(