[英]Nested template explicit specialization
我有一些編譯器行為——在 VisualC++ 和 g++ 上不同——我不明白(對於任何一個編譯器)。 我將用英語描述它,但也許只看下面的代碼會更容易。
它與具有成員類模板和成員函數模板的類模板有關。 我正在嘗試同時
我發現,有兩種編譯器,一切編譯罰款(和實例都如預期),如果我做任何#1(明確專業外類模板)或#2(明確專門成員模板)。
但是,如果我嘗試同時執行 #1 和 #2(以我認為的正確順序聲明),我發現
這是外部類模板的主要定義。 在以下所有情況下都是相同的:
// Class template with a member class template and a member function template
template <int I>
struct OuterClass
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
這里只做 #1(顯式專門化外部類模板)。 這可以很好地編譯並且實例化符合預期。
// Explicit specialization of outer class template,
// leaving member templates unspecialized.
template <>
struct OuterClass<1>
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
這里只做 #2(明確專門化成員模板)。 這可以很好地編譯並且實例化符合預期。
// Explicit specialization of inner templates for
// an explicit specialization of outer class template
template <> template <> struct OuterClass<1>::InnerClass<1> {};
template <> template <> void OuterClass<1>::InnerFunc<1>() {}
這是嘗試同時執行 #1 和 #2 - 只需將前面的兩個代碼片段粘貼在一起:
// Explicit specialization of outer class template,
// leaving member templates unspecialized.
template <>
struct OuterClass<1>
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
// Explicit specialization of inner templates for
// an explicit specialization of outer class template
template <> template <> struct OuterClass<1>::InnerClass<1> {}; // Line A
template <> template <> void OuterClass<1>::InnerFunc<1>() {} // Line B
g++ 可以很好地編譯“A 行”(並且實例化符合預期)。 但是 g++ 給出了 B 行的編譯器錯誤:“模板參數列表太多”。
VC++ 給出了“A 行”和“B 行”的編譯器錯誤(太雜亂太多,無法在此詳述)。
同樣,當“A 行”和“B 行”沒有出現在外部類模板的顯式特化之后,這兩個編譯器都可以很好地編譯。
根據我的理解,一切都應該可以正常編譯。 那么誰是對的——我、g++ 還是 VC++? 更重要的是,為什么?
請理解這不是“我如何完成 X”的問題,而是“我想完全理解 C++”的問題。 如果你花時間通讀並思考它,你有我的感謝......我希望我盡可能地把它歸結起來。
我在這個問題上花費了大量時間,我想我已經弄清楚了 - “弄清楚”的意思是我確切地知道在我嘗試過的兩個編譯器(MSVC 和 g++)上什么會編譯什么不會編譯,以及每個編譯器使用什么語法。 這一切都很丑陋,但它是可預測和可重復的——我有很多示例代碼沒有在這里顯示,我從中推斷出結果。 為了清楚起見並避免我感到沮喪,這里的描述不是我的理論,它是編譯器在數百個示例案例中觀察到的行為。
在高層次上:
我在這里給出的詳細描述可能過於簡短,普通讀者無法理解,但無論如何我都會嘗試。
下面是一些示例代碼,顯示了在定義具有特定專業化鏈的嵌套類模板時,“template<>”必須出現的次數。 這在 MSVC 和 g++ 上編譯(使用條件編譯)。 此代碼不涉及嵌套函數模板。
#include <boost\predef.h> // For conditional compilation
// Nested class templates, 3 deep.
template <int I1> struct T1
{
template <int I2> struct T2
{
template <int I3> struct T3 {};
};
};
// Specialization of the third level of class template.
// "template<>" appears three times here for both MSVC and g++ -
// in this case the rules for both compilers both yield 3.
// Note this class template specialization nests another 2 levels of class templates.
template <> template <> template<> struct T1<1>::T2<1>::T3<1>
{
template <int I4> struct T4
{
template <int I5> struct T5 {};
};
};
// Specialize the class template contained in the class template specialization above.
// In this case, the number of times "template<>" must appear differs between MSVC and g++,
// so conditional compilation is used.
#if BOOST_COMP_GNUC
// According to the rule described for g++, "template<>" must appear 4 times:
// (Overall specialization level of 5) - (1 covering specialization which is T1<1>::T2<1>::T3<1>) = 4
template <> template<> template<> template<> struct T1<1>::T2<1>::T3<1>::T4<1>::T5<1>
#elif BOOST_COMP_MSVC
// MSVC uses the last hop specialization rule, so "template<>" must appear 2 times -
// because the closest covering specialization, T1<1>::T2<1>::T3<1>, is two hops back.
template <> template<> struct T1<1>::T2<1>::T3<1>::T4<1>::T5<1>
#else
#error Unsupported compiler!
#endif
{
//...
}
這里的問題(就像你的另一個問題一樣)是,一旦為(整個)類模板聲明了顯式特化,該特化在語法上就是一個普通類(盡管名稱包含標點符號):
template<int> struct A {
void f();
};
template<int I> void A<I>::f() {}
// A specialization of only a member does use template<>:
template<> void A<0>::f() {/*...*/}
template<> struct A<1> {
void g();
};
// A definition of a member of a specialization doesn't use template<>:
void A<1>::g() {}
將相同的邏輯應用於成員模板會產生
template<int> struct A {
template<class> void f();
template<> void f<void>() {}
};
template<int I> template<class T> void A<I>::f() {}
template<> template<class T> void A<0>::f() {/*...*/}
template<> template<> void A<-1>::f<short>() {/*...*/}
// template<int I> template<> void A<I>::f<int>() {/*...*/}
template<> struct A<1> {
template<class> void g();
};
template<class T> void A<1>::g() {}
template<> void A<1>::g<char>() {/*...*/}
注釋掉的可能性不起作用:您不允許在該類模板之外專門化(非專門化)類模板的成員模板,盡管您可以在模板內部這樣做(盡管 GCC 和 ICC 不實現這一點)或為一個完整的類模板特化的成員模板。
如果在完全專業化的情況下,成員碰巧具有相同的名稱,則像這樣的示例當然有點違反直覺。 在存在編譯器錯誤的情況下,它們也會更加混亂!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.