2013-03-17 85 views
4

我想在我的程序中使範圍枚舉類似於基礎類型,但下面的代碼不起作用。是否因爲我正在使用的編譯器(VC11)中的C++ 11標準支持不佳,還是因爲代碼違反了C++ 11標準中的一些規則?在後一種情況下,哪些規則正在被破壞(歡迎引用具體的標準條款)?使範圍枚舉類似於基礎類型

#include <type_traits> 
enum class Test: short int { A,B,C }; 
template<typename E> bool operator != (E e, typename std::underlying_type<E>::type n) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 
template<typename E> bool operator != (typename std::underlying_type<E>::type n, E e) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 
int main() 
{ 
    short int x = 123; 
    x != Test::B; // compilation error 
} 

這就是爲什麼我認爲我的代碼應該符合C++ 11的原因。從C++ 11標準的A引號(14.8.3.1):

對於每個功能模板,如果參數推導和檢查成功,則模板參數 (推斷和/或顯式的)用於合成的聲明一個功能模板 專門化,它被添加到候選函數集中用於重載解析。如果>,對於給定的函數模板,參數推導失敗,則不會將此類函數添加到該模板的>候選函數集。

編輯。我的代碼不符合C++ 11(感謝Vaughn Cato和Andy Prowl的解釋)。 Andy Prowl的答案提供了替代工作代碼。

P.S.畢竟我最終使未範圍枚舉範圍的使用命名空間:

namespace Test_ { 
    enum Test { A,B,C }; 
}; 
using Test_::Test; 

namespace Test2_ { 
    enum Test2 { Z,Y,B }; 
}; 
using Test2_::Test2; 

回答

1

第14.8.2段的C++ 11個標準狀態8:

如果無效類型或表達的取代產生,類型推導失敗。無效的類型或表達式 是一種使用替代參數編寫的格式不正確的文件。 [注意:訪問檢查完成爲 部分替換過程。 - 結束註釋] 只有在 的上下文中,無效的類型和表達式纔會導致函數類型及其模板參數類型失敗。 [注意:替換類型和表達式的評估 可能導致副作用,例如類模板專業化和/或功能模板專業化的實例化,隱式定義函數的生成等。 此類副作用不是在「緊急情況下」,並可能導致該計劃不合格。 - 結束 注]

在你的情況,實例化underlying_type導致失敗,而不是在直接背景,所以它不是一個類型推導失敗,所以SFINAE不適用。

4

你可以使用SFINAE排除你的比較運營商簽名的實例化(並因此std::underlying_type<T>實例化)時,相應的參數是枚舉:

#include <type_traits> 

template<typename E, 
    typename std::enable_if<std::is_enum<E>::value>::type* = nullptr> 
bool operator != (E e, typename std::underlying_type<E>::type n) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 

template<typename E, 
    typename std::enable_if<std::is_enum<E>::value>::type* = nullptr> 
bool operator != (typename std::underlying_type<E>::type n, E e) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 

這裏是一個live example

編輯:

由於VC11似乎缺少一個函數模板的模板參數默認參數的支持,這裏是一個替代的解決方案:

template<typename E> 
typename std::enable_if<std::is_enum<E>::value, bool>::type 
operator != (E e, typename std::underlying_type<E>::type n) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 

template<typename E> 
typename std::enable_if<std::is_enum<E>::value, bool>::type 
operator != (typename std::underlying_type<E>::type n, E e) 
{ 
    return static_cast<typename std::underlying_type<E>::type>(e) != n; 
} 

當然的live example

+0

@PowerGamer:這能解決你的問題嗎? – 2013-03-17 13:06:09

+0

完全沒有,因爲我沒有要求可能的解決方法,因爲在特定編譯器中缺少C++ 11支持,而是爲了確認我的代碼是否符合C++ 11(您的代碼不起作用無論如何,因爲VC11缺少對函數模板的默認模板參數的支持)。但是你提到的SFINAE確實幫助我更好地理解了我自己編寫的代碼:)現在我認爲它應該符合C++ 11(儘管如此,仍然需要知道一個人的確認),以及它不起作用的原因VC11是因爲它缺乏表達SFINAE的支持。 – PowerGamer 2013-03-17 13:32:42

+0

@PowerGamer:你的代碼在任何編譯器上都不起作用([see here](http://liveworkspace.org/code/4cvdpz$60)),這正是我在前面的評論中解釋的原因(我刪除,因爲你刪除了你的請求澄清)。這不是關於缺乏支持,你的代碼根本無法工作。可能VC11缺少對模板參數的默認參數的支持,這就是爲什麼* my *解決方案無法在VC11上運行的原因。我不知道。但它可以解決。讓我編輯。 – 2013-03-17 13:36:03