以下最小可重現示例包含一個模板struct B,其默認引數型別包含一個 lambda A<[]{ return 1; }>,B遞回繼承自B<>. 并且有一個Bfor any的專業化A<z>。
template<auto>
struct A{};
template<class = A<[]{ return 1; }>>
struct B : B<> {};
template<auto z>
struct B<A<z>> {};
B<int> x;
GCC 對這個例子沒問題,Clang 抱怨道:
error: implicit instantiation of template 'B<A<{}>>' within its own definition
演示:https : //gcc.godbolt.org/z/xzjzo7dE9
哪個編譯器在這里?
PS如果修改B這種方式的定義:
template<class>
struct B : B<A<[]{ return 1; }>> {};
然后所有編譯器都變得非常高興,演示:https : //gcc.godbolt.org/z/roqnc39eq
uj5u.com熱心網友回復:
哪個編譯器在這里?
兩者都是,因為B格式不正確;NDR。與往常一樣, [temp.res]/8 適用:
可以在任何實體化之前檢查模板的有效性。該程式格式錯誤,不需要診斷,如果:
(8.4) - 由于不依賴于模板引數的構造,緊隨其定義的模板的假設實體化將是格式錯誤的,或者
模板是B,這里的“它的”定義是主要的。如果我們在B<>之后立即實體化,我們將得到一個無條件格式錯誤的類定義。因此,GCC 和 Clang 可以做任何事情。
順便說一句,整個 lambda 作為模板引數業務是一個紅鯡魚。我們可以使用普通的、舊的 int 作為引數,也可以得到類似的分歧。
template<int>
struct A{};
template<class = A<0>>
struct B : B<> {};
template<int z>
struct B<A<z>> {};
B<int> x;
int main() {}
Clang 仍然抱怨,但現在GCC 也是如此。
uj5u.com熱心網友回復:
是的,由于https://timsong-cpp.github.io/cppwp/n4868/temp.res#general-8.4,原始程式格式錯誤。
可以通過提前移動模板專業化來修復它:
template<auto>
struct A{};
template<class = A<[]{ return 1; }>>
struct B;
template<auto z>
struct B<A<z>> {};
template<class>
struct B : B<> {};
B<int> x;
現在 Clang 和 GCC 都接受了:https : //gcc.godbolt.org/z/6TYdvTnMa
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/405356.html
標籤:
上一篇:如何用模板型別宣告概念函式簽名?
