2015-09-08 63 views
7

我有一個模板函數,其中枚舉類型轉換爲其基礎類型,但工作正常,但我寫了一個重載應該採取一個整數並返回自身,它給我一個int不是枚舉類型的錯誤。在我的模板中,這應該被過濾掉。哪裏不對?從類型到相同類型的「轉換」導致錯誤

這裏是模板代碼:

template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
    { 
     return t; 
    } 

    template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value, typename std::underlying_type<TT>::type>::type 
    { 
     return (typename std::underlying_type<TT>::type)t; 
    } 

Demo

+1

我不知道'underlying_type'是SFINAE友好,但有一個[解決方法](http://coliru.stacked-crooked.com/a/e7f1dd3b75c8d9c2)爲 –

+0

什麼?我看到它有效,但是這裏發生了什麼,使它起作用了?爲什麼SFINAE友好的'underlying_type'不會? – Adrian

+1

「std :: underlying_type :: type」的實例化被推遲,所以'enable_if'可能首先失敗。 * * SFINAE友好的*我的意思是任何替換失敗都只發生在緊接着的上下文中(如果它發生在'underlying_type'本身內部,它不是SFINAE友好的)。 –

回答

4

std::underlying_type<TT>::typestd::enable_if即使std::is_enum<TT>::valuefalsefalse是不是一個錯誤被評估。由於正在評估非枚舉類型,因此會導致錯誤。如果我們將SFINAE移入模板參數中,我們可以得到所需的重載並仍然返回正確的類型。

template <typename TT, typename std::enable_if<!std::is_enum<TT>::value, TT>::type* = nullptr> 
static constexpr auto get_value(TT t) -> TT 
{ 
    return t; 
} 

template <typename TT, typename std::enable_if<std::is_enum<TT>::value>::type* = nullptr> 
static constexpr auto get_value(TT t) -> typename std::underlying_type<TT>::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

你可以看到它在這個Live Example

+0

因此,爲了確保我正確理解這一點,第二個模板參數是一個類型爲'void *'的未命名參數,如果is /不是枚舉類型(取決於我想要的)導致創建,而非實體if不是我想要的,然後會被拒絕? – Adrian

+0

@Adrian如果'std :: enable_if'成功'type'是void,那麼我們可以爲SFINAE設置一個類型爲'nullptr'的指針 – NathanOliver

+0

@dyp我編輯了答案。它應該解決現在的實際原因。 – NathanOliver

4

工作正常,嘗試實例std::underlying_type<T>T這不是一個枚舉類型,你違反了該標準的模板參數T規定要求:

§20.10.7.6 [meta.trans.other] /表57:

 Template   |   Condition   |  Comments 
------------------------+---------------------------+----------------------- 
template <class T>  | T shall be an enumeration | The member typedef 
struct underlying_type; | type (7.2)    | type shall name 
         |       | the underlying type 
         |       | of T. 

這裏的,如果一個人不喜歡任何額外的模板參數的另一種方法:

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
{ 
    return t; 
} 

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value 
          , std::underlying_type<TT> 
       >::type::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

這樣,std::underlying_type<TT>實例化被推遲,直到std::enable_if條件值爲true,因爲嵌套type定義請求爲什麼std::enable_if<B,T>::type返回。

DEMO

+0

因此,只有當您獲得'std :: underlying_type :: type'類型而不需要'std :: underlying_type '本身時才需要該需求?這是爲什麼? – Adrian

+1

@Adrian'std :: underlying_type '僅在用作類型模板參數時未實例化 –