2013-05-04 49 views
4

我有一個模板化的類,只能爲標量類型(整數,浮點數等)實例化,我想要一個成員typedef始終是類型的簽名變體。那就是:std :: make_signed接受浮點類型

unsigned int - >signed int
signed long long - >signed long long(已簽署)
unsigned char - >signed char
float - >float
long double - >long double
etc ...

不幸的是,std::make_signed只適用於整型類型,而不是浮點類型。什麼是最簡單的方法來做到這一點?我正在尋找using SignedT = ...;的形式,作爲我的模板類的一部分,模板參數T已經保證是標量。

回答

8

一個簡單的模板別名會做:

#include <type_traits> 

template<typename T> 
struct identity { using type = T; }; 

template<typename T> 
using try_make_signed = 
    typename std::conditional< 
     std::is_integral<T>::value, 
     std::make_signed<T>, 
     identity<T> 
     >::type; 

這是你如何能測試:

int main() 
{ 
    static_assert(::is_same< 
     try_make_signed<unsigned int>::type, int 
     >::value, "!"); 

    static_assert(std::is_same< 
     try_make_signed<double>::type, double 
     >::value, "!"); 
} 

這是live example

+0

我更喜歡用'std :: common_type '來創建自己的'identity'類;} – 2013-05-04 19:21:11

+0

+1,'using'很方便,我需要最後更新我的編譯器:) – jrok 2013-05-04 19:31:55

3

在我最初嘗試使用std::conditional之後,我決定改用SFINAE。我使用std::enable_if到conditionaly啓用浮點類型專業化:

template<typename T, typename Enable = void> 
struct my_make_signed { 
    typedef typename std::make_signed<T>::type type; 
}; 

template<typename T> 
struct my_make_signed<T, 
    typename std::enable_if<std::is_floating_point<T>::value>::type> { 
    typedef T type; 
}; 
+0

如果'make_signed'不專用於'T',那麼這不會產生錯誤嗎? (這就是'float'的情況)。 – mfontanini 2013-05-04 19:02:30

+0

@mfontanini我不好,現在不會。感謝您的高舉。 – jrok 2013-05-04 19:05:00

+0

不客氣:D。但是現在,您的條件將根據條件的結果生成'std :: make_signed '(應用':: type'確定)或'T'(例如可以是浮點數)。 – mfontanini 2013-05-04 19:07:47

0
namespace mine {   

    template<typename T, bool b> 
    struct make_signed__ { 
     typedef T type; 
    }; 

    template<typename T> 
    struct make_signed__<T,false> { 
     typedef typename std::make_signed<T>::type type; 
    }; 

    template<typename T> 
    struct make_signed { 
     typedef typename make_signed__<T, std::is_floating_point<T>::value>::type type; 
    }; 

} 

int main() { 
    std::cout << std::is_same<mine::make_signed<unsigned int>::type, int>::value; 
    std::cout << std::is_same<mine::make_signed<long double>::type, long double>::value; 
} 
+0

這不是很便攜,因爲它可以' t支持任意支持的類型(例如,編譯器可以支持'std :: uint512_t',客戶端代碼可以實例化我的類) – 2013-05-04 19:23:14

+0

@ LB--是的。但他只需要確定他使用的是什麼。順便說一句'std :: make_signed'支持那些? – stardust 2013-05-04 19:26:58

+0

是的,它必須是因爲它是由編譯器實現定義的。 – 2013-05-04 19:30:28

2

@jrok最初有代碼可以工作,他只需要做一個小調整。這是工作的代碼:

template<typename T> 
struct YourClass 
{ 
    using SignedT = 
     typename std::conditional 
     < 
      std::is_floating_point<T>::value, //if floating point type 
      std::common_type<T>,    //use it as-is 
      std::make_signed<T>    //otherwise make sure it is signed 
     >::type::type; //notice the double ::type 
}; 

演示:http://ideone.com/Vw7o82

上述結構也可以被修改,以本身是一種類型的性狀類,如果這種功能需要被多次使用。然而,@Andy Prowl的回答是用別名模板來做的,這樣更好。

+0

這可以工作,但它的缺點是你必須每次定義它。使用我的答案中的別名模板,您可以只使用'SignedT = typename try_make_signed :: type',就完成了。 – 2013-05-04 19:41:12

+0

這個答案中的類很容易被重構爲一個類型特徵類,所以我不知道你的意思是'缺點' - 如果我們的答案是一樣的話,對嗎? – 2013-05-04 19:44:36

+0

夠公平的,你可以修改它來創建一個類型特徵,是的 - 如果使用別名模板完成,就更好了,就像在我的回答中一樣 – 2013-05-04 19:47:20