2014-03-01 22 views
0

我想根據給定的類型製作std::uniform_*_distribution的特性。例如:使用enable_if與is_integral來製作分配特性

distribution_traits<float>::type int_dist; 

我試過以下方法,但沒有一個編譯,我不知道爲什麼。

實現1

使用std::enable_iftypedef S:

template <typename T> 
struct distribution_traits { 
    using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type; 
    using type = typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type; 
}; 

鏘3.4抱怨:

dist_traits.cpp:7:9: error: redefinition of 'type' 
    using type = typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type; 
     ^
dist_traits.cpp:6:9: note: previous definition is here 
    using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type; 
     ^
dist_traits.cpp:6:40: error: no type named 'type' in 'std::enable_if<false, std::uniform_int_distribution<float> >'; 'enable_if' cannot be used to 
     disable this declaration 
    using type = typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type; 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~ 
dist_traits.cpp:28:3: note: in instantiation of template class 'distribution_traits<float>' requested here 
    distribution_traits<float>::type int_dist; 
^
2 errors generated. 

實現2

使用enable_if作爲類模板參數:

template <typename T, typename distribution_t = void> 
struct distribution_traits; 

template <typename T> 
struct distribution_traits< 
    T, typename std::enable_if<std::is_integral<T>::value, 
         std::uniform_int_distribution<T> >::type > { 
    using type = std::uniform_int_distribution<T>; 
}; 

template <typename T> 
struct distribution_traits< 
    T, typename std::enable_if<std::is_floating_point<T>::value, 
         std::uniform_real_distribution<T> >::type > { 
    using type = std::uniform_real_distribution<T>; 
}; 

而且鏘抱怨

dist_traits.cpp:28:3: error: implicit instantiation of undefined template 'distribution_traits<float, void>' 
    distribution_traits<float>::type int_dist; 
^

無論如何不能被MSVC++ 12.0編譯,並且錯誤消息是相似的。

任何人都可以請解釋我在用SFINAE做什麼錯?謝謝!


對於那些誰是好奇的解決方案,下面是編譯一個:

template <typename T> 
auto dist() -> typename std::enable_if<std::is_integral<T>::value, std::uniform_int_distribution<T>>::type; 

template <typename T> 
auto dist() -> typename std::enable_if<std::is_floating_point<T>::value, std::uniform_real_distribution<T>>::type; 

template <typename T> 
struct distribution_traits { 
    using type = decltype(dist<T>()); 
}; 

順便說一句,如果把dist功能分爲distribution_traits,編譯將失敗,錯誤:函數只不同的回報類型不能重載。 :(

+1

改爲使用'std :: conditional'。 – Rapptz

+0

@Rapptz謝謝!使用'std :: conditional',可以寫'使用type = typename std :: conditional :: type'。更好的代碼! –

回答

1

SFINAE可以使用模板參數替換時丟棄的函數模板和類模板特重載。

它不能與類型/模板別名,就像你正在試圖做的使用。

關於你的工作代碼 - 把dist類裏面,因爲你嘗試調用distdecltype無一物不工作使dist靜,它會工作:

template <typename T> 
struct distribution_traits { 
    template <typename U> 
    static auto dist() -> typename std::enable_if<std::is_integral<U>::value, std::uniform_int_distribution<U>>::type; 

    template <typename U> 
    static auto dist() -> typename std::enable_if<std::is_floating_point<U>::value, std::uniform_real_distribution<U>>::type;  

    using type = decltype(dist<T>()); 
}; 

爲了實現2到工作中,你需要忽略的enable_if第二個參數:

模板 結構distribution_traits;

template <typename T> 
struct distribution_traits< 
    T, typename std::enable_if<std::is_integral<T>::value>::type> { 
    using type = std::uniform_int_distribution<T>; 
}; 

否則你定義專業化是distribution_traits<T, uniform_int_distribution<T>>因爲第二個參數默認爲void不匹配像distribution_traits<float>一個實例。