2017-02-09 70 views
2

考慮這個簡單的模板專業化:模板偏特非類型參數:GCC VS MSVS

template<typename T, size_t I> 
struct S {}; 

template<typename T> 
struct S<T, std::tuple_size<T>::value> {}; 

GCC不能編譯它,因爲它使用模板參數T在模板參數std::tuple_size<T>::value

error: template argument 'std::tuple_size<_Tp>::value' involves template parameter(s)

現在,讓我們在tuple_size模板參數與typename std::remove_reference<T>::type替換T

// Using primary structure template from previous example. 
template<typename T> 
struct S<T, std::tuple_size<typename std::remove_reference<T>::type>::value> {}; 

該代碼仍然在模板參數中使用模板參數,但GCC編譯時沒有任何錯誤或警告。爲什麼?

non-type parameter of a partial specialization must be a simple identifier

這是什麼奇怪的限制:

現在,如果我們試圖編譯使用MSVS的第二個例子是/std:c++latest標誌,它與錯誤C2755停止?當I等於元組大小時,我想停止編譯時遞歸。

那麼他們是誰錯了:MSVS還是GCC?

注意MSVS即使沒有任何模板實例報告錯誤,而GCC正常工作與所有這些實例:

S<std::tuple<int, float>, 9> s1; 
S<std::tuple<int, float>, 2> s2; 
S<int, 42> s3; 

我使用MSVS社區2015年更新3與它的默認編譯器和GCC 6.2.1。

嘗試鏗鏘3.8.0。它不具有類似於GCC的消息的錯誤編譯兩個片段:

error: non-type template argument depends on a template parameter of the partial specialization

回答

3

處理部分類模板特化的可行性標準的特定部分已在過去幾年改變了很多次。原restrictionin [temp.class.spec.match]讀:

A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

您的代碼明確運行相抵觸的是,std::tuple_size<T>::value不是標識符。

它再變,cwg issue 1315後,將其改爲:

Each template-parameter shall appear at least once in the template-id outside a non-deduced context.

但我們現在還好吧 - T是在非推斷上下文的第一個模板參數使用。和template auto之後,它現在讀取:

If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.

但我們還好有太多。可以推論,你有正確的「結構」 - 你的專業化在主要位置使用一個非類型的模板參數,它們應該很好地匹配。


我認爲以下的1315的分辨率(我認爲這是 -C++ 14),所述代碼應良好的,但兩者gcc和鐺拒絕它。不幸的解決將是使用兩個參數代替:

template <class T, class I> 
struct S; 

template<typename T> 
struct S<T, typename std::tuple_size<T>::type> {}; 

template <size_t I> 
using size_ = std::integral_constant<size_t, I>; 

int main() { 
    S<std::tuple<int>, size_<1>> s; 
} 

GCC和鏗鏘接受一個。