2016-05-13 80 views
6

考慮下面的代碼:模板偏特和ICC

template <class T, class U, class V> 
struct Foo { }; 

template <class T, class U> 
struct Foo<T, U, std::integral_constant<int, U::value>> { 
    static void print() 
    { 
    std::cerr << "instantiated"; 
    } 
}; 

template <class U> 
struct Foo<double, U, std::integral_constant<int, U::value>> { 
    static void print() 
    { 
    std::cerr << "instantiated special"; 
    } 
}; 

struct Bar { 
    static const int value = 0; 
}; 

int main(int argc, char ** argv) 
{ 
    using Baz = Foo<double, Bar, std::integral_constant<int, 0>>; 
    Baz::print(); 

    return 0; 
} 

當我編譯這個使用ICC 16.0.1,我得到以下信息:

main.cpp(38): error: more than one partial specialization matches the template argument list of class "Foo<double, Bar, std::integral_constant<int, 0>>" 
      "Foo<T, U, std::integral_constant<int, U::value>>" 
      "Foo<double, U, std::integral_constant<int, U::value>>" 
    Baz::print(); 

鏗鏘3.7.1和gcc 5.3.0編譯(和「實例化特殊」打印)。這是icc中的錯誤,還是我的代碼不正確?對我來說,似乎很清楚,第二個專業比第一個專業嚴格得多。它與第一個完全相同,而不是鎖定第一個模板參數。

編輯:我應該補充:如果這是icc中的錯誤,是否有一個很好的解決方法?

+0

當然看起來像icc中的一個bug給我。 – Cameron

+0

您能否檢查[下面的評論](https://stackoverflow.com/questions/37216212/partial-template-specialization-and-icc#comment61972971_37216503)中的建議是否解決了ICC上的問題?當然,對於您的問題不是一個完整的解決方案,只是向前邁進了一步。 – bogdan

+0

在實際的代碼中,整數來自U的嵌套成員,這反過來又給了叮噹問題,所以我的同事從非類型轉換爲類型模板參數。 –

回答

4

是的,這是ICC中的一個錯誤。


兩個部分特例匹配您的實現,因此進入局部模板排序規則在兩個合成功能:

template <class T, class U> void f(Foo<T, U, std::integral_constant<int, U::value>); 
template <class U>   void f(Foo<double, U, std::integral_constant<int, U::value>); 

局部排序規則涉及合成新的類型爲每個模板參數,並試圖做每個超負荷與其餘部分相抵扣。首先,我們試圖根據Foo<_U1, _U2, std::integral_constant<int, _U2::value>>推導U。這失敗了,因爲_U1不符合double。所以第一次重載並不像第二次那麼專業。接下來,我們試圖針對Foo<double, _U3, std::integral_constant<int, _U3::value>>推導出TU。這成功與T=doubleU=_U3。所以第二次重載至少與第一次重載一樣。

因此,第二次過載比第一次更專門。有一個獨特的最專業的局部偏分,這是應該實例化(並通過gcc和clang)。 ICC沒有這樣做是一個錯誤。

+0

部分排序和未推導的上下文再次工作......用推導出的'int I'替換'U :: value'將最有可能使事情按預期工作。它看起來像EDG前端(最有可能在這裏被ICC使用)與MSVC一致,並且由於未推斷的上下文而使得過載至少與其他專用一樣。令人擔憂的是,我在其「 - 嚴格」模式下測試了非MSVC怪癖EDG,它仍然執行相同的操作。在編譯器去的時候,它是2。太好了。 – bogdan

+0

@bogdan爲什麼會導致演繹失敗? – Barry

+0

我的確同意,在解釋中的第二步中扣除失敗是沒有意義的。我只是指出,非推斷的上下文很可能是問題的原因(我對EDG的行爲感到非常驚訝)。我會要求OP檢查是否將'U :: value'更改爲'0'(或如上所述),以解決ICC上的問題。 – bogdan