![](/img/trans.png)
[英]template class partial specialization with different non-type template parameter
[英]Partial specialization of single type template parameter class template using non-type template parameter through a dependent type
以下所有標准參考均指N4659:2017 年 3 月 Kona 后工作草案/C++17 DIS 。
考慮以下代碼段:
#include <type_traits>
template <int N> struct num {};
template <typename> struct A;
// (1)
template <int N> struct A<num<N>> { using type = bool; };
// (2)
template <long N> struct A<num<N>> { using type = char; };
static_assert(!std::is_same_v<long, int>, "");
// (A)
static_assert(std::is_same_v<A<num<1>>::type, bool>, "");
int main() {}
(A)處的static_assert
對於 GCC 是成功的,但對於 Clang 是失敗的:
error: static_assert failed due to requirement 'std::is_same_v<char, bool>' ""
本質上, GCC 選擇了完美匹配的專業化(1) ,而 Clang 選擇了專業化(2) 。
同樣,如果我們刪除斷言以及專業化(1) :
template <int N> struct num {};
template <typename> struct A;
// (2)
template <long N> struct A<num<N>> { using type = char; };
int main() {
A<num<1>> a{};
(void)a;
}
然后 GCC 無法編譯程序,而 Clang 接受它。
GCC:
error: variable '`A<num<1> > a`' has initializer but incomplete type
This behaviour holds over various GCC and Clang versions, as well as various C++ language levels over these version (C++11, C++14, C++17, C++2a).
我的猜測是這是不正確的,但無法應用[temp.class.spec]的相關部分來拒絕它。 也許[temp.class.spec]/8.1 ?
[temp.class.spec]/8.1對應於專門化的非類型實參的模板形參的類型不應依賴於專門化的形參。 [示例:[...] — 結束示例]
據我所知,第一個片段格式不正確(需要診斷); 由於部分專業化(2),編譯器應該拒絕該程序。
如果
P
有一個包含<i>
的表單,並且如果i
的類型與封閉的simple-template-id命名的模板的相應模板參數的類型不同,則推導失敗。 [...]
標准中的相關示例使用 function 模板,但在其他方面非常相似。
因此,部分特化 (2) 的模板參數永遠無法推導出來,並且[temp.class.spec.match]/3適用:
如果部分特化的模板 arguments 由於其模板參數列表和模板標識的結構而無法推導,則程序是非良構的。
有趣的是,我找不到診斷此問題的編譯器,甚至在嚴格模式下也找不到 EDG。 我們可以推測,大多數編譯器編寫者認為在這里進行診斷的好處不值得為實現檢查付出努力。 這可能意味着我們可能會看到上一段中的要求在未來從不規范變為不規范,不需要診斷。 然而,這純屬猜測。 無論如何,我認為它永遠不會變成well-formed ; 我想不出一個從不匹配的部分專業化的有效用途。
CWG2091 的決議澄清了 [ temp.deduct.type ]/18的措辭。
該標准對於部分專業化([temp.class.spec.match]/2)的模板參數推導不夠精確,無法明確確定示例的含義。 特別是,所有推導最終都是根據類型([temp.deduct.type]) 定義的,但非類型模板參數不涉及類型。
偏特化之間偏序的推導根據發明的 class 模板 ([temp.class.order]/1.2) 來處理這種情況,這帶來了對於非類型的類型之間的任何不匹配,推導失敗的規則模板參數及其參數([temp.deduct.type]/18)。 如果兩個部分特化都匹配,那么在您的示例中使用A<num<…>>
會變得模棱兩可(避免需要確定在使用為部分排序而合成的“唯一值”時是否涉及縮小轉換([temp.func. order]/3) 作為模板參數)。 但是,如果我們將相同的規則應用於匹配本身,我們會發現(就像GCC 一樣)(2)永遠不會匹配。 反過來,這可以說應該引起對專業化本身的診斷([temp.class.spec.match]/3,正如博格丹的回答所提到的),盡管如果錯誤是,它意味着什么“結構”並不完全明顯是可診斷的,並且沒有編譯器拒絕它。
同時,[temp.class.spec]/8.1 肯定是無關緊要的:沒有專門的非類型 arguments 涉及。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.