2017-01-03 97 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; 
} 
相关问题