雁过无痕

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::

前几天在水母上看到的题:

正常的比较 assert(-1 < 1U) 是会失败的。因为 -1 会提升成无符号数。
写一个安全的比较函数,使得
template <typename T1, typename T2>
int SafeIntCompare(T1 i1, T2 i2);
如果 i1 真实值 <  i2,返回 -1
     i1 真实值 == i2,返回  0
     i1 真实值 >  i2,返回  1


只有当两个类型一个是有符号、另一个是无符号时,才需要特殊处理。
对类型的符号判断,可以直接判断该类型的-1是否比0小,也可以用标准库std::numeric_limits<T>中的is_signed成员。

简单的做法:
template<typename T1, typename T2>
int SafeIntCompare(T1 v1, T2 v2)
{
  
static const bool t1 = std::numeric_limits<T1>::is_signed;
  
static const bool t2 = std::numeric_limits<T2>::is_signed;
  
if (t1 != t2) {
    
if (t1 && v1 < 0return -1;
    
if (t2 && v2 < 0return 1;
  }
  
if (v1 == v2) return 0;
  
if (v1 < v2)  return -1;
  
return 1;
}

但由于进行比较的两个数可能分别是:有符号数和无符号数,编译时编译器会给出大量的警告。

     要避免有符号数和无符号数的进行直接比较,就必须将它们都转为同一个类型T。这个类型的确定可以采用两种方法:

     1 比较原来两个类型是否是有符号数以及它们所占用的字节数,来推断出应该将它们都转为哪种类型T,这是vc那个safeint的做法。

     2 采用这个trick:将这两个类型的数(数可以取0)直接相加,得到的结果的类型就是所求的。这是因为:两个数进行比较时,采用的类型转换规则和两个数相加时所采用的规则是一致的。


改成后的代码

  但上面的写法有一个问题:如果一个 short和一个unsigned char进行比较,编译器都是转为int进行比较,没有必要进行特殊处理(上面的代码处理后会多一个与0的比较)。实际上,如果两个类型都是转为有符号类型,可以直接进行比较。
最终代码:

template
<typename T>
struct IsSigned { 
  
static const bool value = T(-1< T(0); 
};

template
<bool> struct Assert {};
template
<> struct Assert<false>;

template
<int> struct Type {};
typedef Type
<0> TagNormal;
typedef Type
<1> TagFirstArgIsSigned;
typedef Type
<2> TagSecondArgIsSigned;

template
<typename T1, typename T2, typename T3>
int SafeIntCompare(T1 v1, T2 v2, T3, TagNormal)
{
  
if (v1  < v2) return -1;
  
if (v1 == v2) return 0;
  
return 1;
}

template
<typename T1, typename T2, typename T3>
int SafeIntCompare(T1 v1, T2 v2, T3 v3, TagFirstArgIsSigned)
{
  
if (v1 < 0return -1;
  
return SafeIntCompare(T3(v1), T3(v2), v3, TagNormal());
}

template
<typename T1, typename T2, typename T3>
int SafeIntCompare(T1 v1, T2 v2, T3 v3, TagSecondArgIsSigned)
{
  
if (v2 < 0return 1;
  
return SafeIntCompare(T3(v1), T3(v2), v3, TagNormal());
}

template
<typename T1, typename T2, typename T3>
int SafeIntCompare(T1 v1, T2 v2, T3 v3)
{
  typedef std::numeric_limits
<T1> M1;
  typedef std::numeric_limits
<T2> M2;
  typedef std::numeric_limits
<T3> M3;
  
static const bool is_arg_valid = M1::is_integer & M2::is_integer;
  Assert
<is_arg_valid>();
  
static const int type_idx = M3::is_signed ? 0 : (M1::is_signed + M2::is_signed * 2% 3;
  
return SafeIntCompare(v1, v2, v3, Type<type_idx>());
}


template
<typename T1, typename T2>
int SafeIntCompare(T1 v1, T2 v2)
{
  
return SafeIntCompare(v1, v2, T1(0+ T2(0));
}
posted on 2012-03-30 20:16 flyinghearts 阅读(1812) 评论(4)  编辑 收藏 引用 所属分类: c++模板

评论

# re: 安全的整数比较 2012-04-01 09:26 cloudffx
这么麻烦,还不如用模板特化  回复  更多评论
  

# re: 安全的整数比较 2012-04-01 10:24 zjh
直接c代码就行了  回复  更多评论
  

# re: 安全的整数比较 2012-04-04 20:59 flyinghearts
@cloudffx
不认真看贴。你自己实现下吧。
  回复  更多评论
  

# re: 安全的整数比较 2012-04-04 21:02 flyinghearts
@zjh
C不是万能的


  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理