2017-01-03 32 views
9

我有以下模板:優雅的方式擺脫有符號和無符號整數表達式之間的比較

一個用於未簽名和另一個用於簽名。有沒有優雅的方式擺脫編譯器警告而不壓制它?

warning: comparison between signed and unsigned integer expressions 

我是否需要爲每種類型編寫函數,例如: uint8,uint16等。?

template<typename X,typename Y,typename Z, typename std::enable_if<std::is_unsigned<X>::value, bool>::type = true > 
void debugValidateParameter(X aValueToCheck, Y aLowerLimit, Z aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 

template<typename X,typename Y,typename Z, typename std::enable_if<std::is_signed<X>::value, bool>::type = true > 
void debugValidateParameter(X aValueToCheck, Y aLowerLimit, Z aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 
+1

爲什麼你有X,Y和Z?不應該所有的值都是* one *類型嗎? – JimmyB

+0

比較簽名與無簽名是蘋果比較桔子。 –

回答

12

讓我解釋一下你在這裏弄錯了什麼。

對於我來說,它看起來像你通常會希望使用相同類型的所有三個參數。最直接的解決辦法是這樣的定義:

template<typename X> 
void debugValidateParameter(X aValueToCheck, X aLowerLimit, X aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 

但是,如果你再調用該函數的無符號變量和兩個常量整數,例如:

debugValidateParameter(someUnsignedInteger, 0, 100); 

你會得到,因爲一個錯誤該類型不能推斷 - 對於這一點,與X類型的所有參數需要傳遞完全相同的類型的值。 因此推斷類型X是不明確的,因而不可能的。對我來說,它看起來像你想演繹出合格(「實際價值」)的基礎上第一個參數類型,只是嘗試邊界轉換爲同一類型。換句話說,一些東西,不強迫你寫

debugValidateParameter(someUnsignedInteger, 0u, 100u); 

這可以通過完成禁用類型推演第二個和第三個參數,通過指定類型identity_t<X>,而不是僅僅X,其中identity_t被定義爲

template<typename T> 
struct identity { typedef T type; }; 

template<typename T> 
using identity_t = typename identity<T>::type; 

所以你的函數定義就變成

template<typename X> 
void debugValidateParameter(X aValueToCheck, identity_t<X> aLowerLimit, identity_t<X> aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 

在這裏你可以看到一個Live Demo代碼。

2

您不需要SFINAE或專業化,您只需要X,Y,Z具有相同的符號。所以你可以使用

template<typename T> 
void debugValidateParameter(T aValueToCheck, T aLowerLimit, T aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", 
     aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 

但這需要所有的參數推導爲相同的類型。

爲了避免這種情況,你可能會迫使一些參數是不可抵扣:

template <typename T> struct non_deducible { using type = T; }; 
template <typename T> using non_deducible_t = typename non_deducible<T>::type; 

template<typename T> 
void debugValidateParameter(T aValueToCheck, 
          non_deducible_t<T> aLowerLimit, 
          non_deducible_t<T> aUpperLimit) 
{ 
    if((aValueToCheck > aUpperLimit) || (aValueToCheck < aLowerLimit)) 
    { 
    log("ERROR: ValidateParameters, aValueToCheck = % , aLowerLimit= % , aUpperLimit= % \n", 
     aValueToCheck, aLowerLimit, aUpperLimit); 
    throw(std::out_of_range("Invalid Range")); 
    } 
} 
1

怎麼這樣呢?

#include <iostream> 
#include <type_traits> 
#include <stdexcept> 

template <typename T1, typename T2> 
bool integral_less_than(T1 t1, T2 t2) 
{ 
    static_assert(std::is_integral<T1>::value, ""); 
    static_assert(std::is_integral<T2>::value, ""); 
    // Handle different signedness. 
    if (std::is_unsigned<T1>::value) 
    { 
    if (!std::is_unsigned<T2>::value) 
     return (t2 < 0) ? false : t1 < static_cast<typename std::make_unsigned<T2>::type>(t2); 
    } 
    else 
    { 
    if (std::is_unsigned<T2>::value) 
     return (t1 < 0) ? true : static_cast<typename std::make_unsigned<T1>::type>(t1) < t2; 
    } 
    // Handle same signedness. 
    return t1 < t2; 
} 

template <typename X, typename Y, typename Z> 
void ValidateParameter(X aValueToCheck, Y aLowerLimit, Z aUpperLimit) 
{ 
    if (integral_less_than(aUpperLimit, aValueToCheck) || 
     integral_less_than(aValueToCheck, aLowerLimit)) 
    { 
    std::cout 
     << "ERROR: ValidateParameter():" 
     << " aValueToCheck=" << aValueToCheck 
     << ", aLowerLimit=" << aLowerLimit 
     << ", aUpperLimit=" << aUpperLimit 
     << "\n"; 
// throw(std::out_of_range("Invalid Range")); 
    } 
} 

int main() 
{ 
    ValidateParameter(0, -1, 1); 
    ValidateParameter(0u, -1, 1); 
    ValidateParameter(0, -1, 1u); 
    ValidateParameter(0u, -1, 1u); 
    ValidateParameter(-1, -1, 1); 
    ValidateParameter(-1, -1, 1u); 
    ValidateParameter(1, -1, 1); 
    ValidateParameter(1u, -1, 1); 
    ValidateParameter(1, -1, 1u); 
    ValidateParameter(1u, -1, 1u); 
    ValidateParameter(-2, -1, 1); 
    ValidateParameter(-2, -1, 1u); 
    ValidateParameter(2, -1, 1); 
    ValidateParameter(2u, -1, 1); 
    ValidateParameter(2, -1, 1u); 
    ValidateParameter(2u, -1, 1u); 
    return 0; 
} 
相關問題