我最近試圖創建一個is_class
類,並且需要一種編譯器區分定義轉換運算符的枚舉類型和類類型的方法。看到類,結構和聯合是如何與指向成員函數兼容的唯一類型,我決定讓編譯器確定用於實例化is_class
模板的類型是否與指向成員函數的代碼兼容。在遇到幾個問題後,我決定在與指向成員的指針結合使用時測試枚舉的行爲,並得到一些古怪的結果。下面段示出了第一怪癖:枚舉和指向成員
enum ENUM {};
void Test(void (ENUM::*pmem) (void))
{
/* ... */
}
Test(NULL);
當使用Microsoft Visual C++ 2010編譯,函數定義的指針到構件部分:(ENUM::*pmem)
被高亮顯示爲紅色,鼠標懸停聲明揭示錯誤:
Error: "ENUM" is not a class type
然而,編譯器解析這個段沒有遇到任何錯誤,分配給pmem
NULL
。我很感興趣的是,編譯器可以讓枚舉類型不是類,結構或聯合,因此不能擁有自己的方法。
template<class _Ty>
void Test_Template(void (_Ty::*pmem) (void))
{
/* ... */
}
當然,爲了使用這一功能,就必須顯式限定:創建模板功能時,採用指針到成員的說法,其類型而異
的第二興趣點出現了:
Test_Template<ENUM>(NULL);
這個調用然而,會產生錯誤,指出:
invalid explicit template argument(s) for 'void Test(void (__thiscall _Ty::*)(void))'
我通過創建一個附加函數模板解決了這個問題,該模板的原型將匹配任何調用失敗的匹配原模板函數的原型(涉及使用省略號)。
問題:
爲什麼是指針到成員兼容枚舉?
爲什麼在調用非模板
Test
函數時存在完全匹配,而編譯器爲模板生成了錯誤Test_Template
顯式限定?
它看起來像'T ENUM :: * D;'是一個語法上有效的聲明。我找不到任何明確表示它在語義上不合格的東西。但是,如果格式良好,那麼它將是一個聲明,其中第8節沒有指定'D'的類型,這很奇怪。 – aschepler 2011-03-05 20:53:47
感謝這個問題,很高興看到超出基本水平的問題偶爾會發生,並且這個問題讓我的頭腦開始攪動:) – 2011-03-05 21:03:57
g ++ 4.4.5 -std = C++ 0x同樣接受'Test',但是在一個試圖調用'Test_Template(static_cast (0))'給出錯誤「沒有匹配函數調用Test_Template(void(ENUM :: *)())」「 –
aschepler
2011-03-05 22:34:12