加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

参数列表中的C隐式类型转换

发布时间:2020-12-16 07:29:03 所属栏目:百科 来源:网络整理
导读:关于C参数列表的隐式类型转换是如何工作的我很困惑.特别是,我有一些函数,如inRange(x,start,end),它们返回一个bool,具体取决于x是否在start和end之间. [在这个描述中,范围只是(x start x end)的语法糖 - 当x是一个长字符串或一个昂贵的函数时它仍然很好 - 但
关于C参数列表的隐式类型转换是如何工作的我很困惑.特别是,我有一些函数,如inRange(x,start,end),它们返回一个bool,具体取决于x是否在start和end之间.

[在这个描述中,范围只是(x> start&& x< end)的语法糖 - 当x是一个长字符串或一个昂贵的函数时它仍然很好 - 但在实际代码中有额外的用于处理边界的开放/封闭性质的方法. 我对上面的类型很模糊.特别是整数和浮点比较有不同的实现,这意味着模板不是很合适,因为没有C语言分组将int / long / unsigned / size_t等区别于float / double等等.所以我尝试过通过使用足够宽的int / float类型定义两个版本的inRange来使用类型系统:

inline bool inRange(long x,long start,long end)
inline bool inRange(double x,double start,double end)

这不会“长久”或类似,但我们的代码最多只使用双倍和长.所以它看起来很安全:我希望inRange(int,long,long)等会隐式地将int转换为long,一切都会好的.但是,如果为浮点比较(我想要允许)写入双字的双字,则例如,inRange(mydouble,10,20),我还必须添加一堆显式转换来摆脱编译器警告并确保使用浮点比较:

inline bool inRange(double value,long low,long high) {
  return inRange(value,(double)low,(double)high);
}
inline bool inRange(double value,double low,low,(double)high,lowbound,highbound);
}
...

不太好 – 我希望将long转换为double会自动/隐含 – 但是没问题.但是下一个发现真的搞砸了我:我的编译器遇到了一个带有三个整数(不长)的inRange作为参数,并说:

call of overloaded ‘inRange(int&,int&,int&)’ is ambiguous

然后是到目前为止定义的所有inRange函数的列表!所以C没有(int,int,int)arg列表的首选项(长,长,长)而不是(double,double,double)?真?

任何让我脱离这个洞的帮助都会非常感激……我从来没有想过这么简单的东西,只涉及原始类型可能会变得如此难以解决.使用所有可能的数字类型组合制作全套~1000三个arg函数签名并不是我希望的答案!

解决方法

模板是这里的基础知识,你只需要一些SFINAE.

#include <limits>
#include <utility>

template <typename T>
struct is_integral {
  static bool const value = std::numeric_limits<T>::is_integer;
};

template <typename Integral,typename T>
typename std::enable_if<is_integral<Integral>::value,bool>::type
inRange(Integral x,T start,T end) {
  return x >= static_cast<Integral>(start) and x <= static_cast<Integral>(end);
}

template <typename Real,typename T>
typename std::enable_if<not is_integral<Real>::value,bool>::type
inRange(Real x,T end) {
  return x >= static_cast<Real>(start) and x <= static_cast<Real>(end);
}

理论上,我们可以更宽松,只允许开始和结束有不同的类型.如果我们想.

编辑:更改为只要有一个真实版本切换到真实版本,内置完整性检查.

#include <limits>
#include <utility>
#include <iostream>

template <typename T>
struct is_integral {
  static bool const value = std::numeric_limits<T>::is_integer;
};

template <typename T>
struct is_real {
  static bool const value = not is_integral<T>::value;
};

template <typename T,typename L,typename R>
struct are_all_integral {
  static bool const value = is_integral<T>::value and
                            is_integral<L>::value and
                            is_integral<R>::value;
};

template <typename T,typename R>
struct is_any_real {
  static bool const value = is_real<T>::value or
                            is_real<L>::value or
                            is_real<R>::value;
};


template <typename T,typename R>
typename std::enable_if<are_all_integral<T,L,R>::value,bool>::type
inRange(T x,L start,R end) {
  typedef typename std::common_type<T,R>::type common;
  std::cout << "  inRange(" << x << "," << start << "," << end << ") -> Integraln";
  return static_cast<common>(x) >= static_cast<common>(start) and
         static_cast<common>(x) <= static_cast<common>(end);
}

template <typename T,typename R>
typename std::enable_if<is_any_real<T," << end << ") -> Realn";
  return static_cast<common>(x) >= static_cast<common>(start) and
         static_cast<common>(x) <= static_cast<common>(end);
}

int main() {
  std::cout << "Pure casesn";
  inRange(1,2,3);
  inRange(1.5,2.5,3.5);

  std::cout << "Mixed int/unsignedn";
  inRange(1u,3);
  inRange(1,2u,3u);

  std::cout << "Mixed float/doublen";
  inRange(1.5f,3.5);
  inRange(1.5,2.5f,3.5f);

  std::cout << "Mixed int/doublen";
  inRange(1.5,3.5);

  std::cout << "Mixed int/double,with more doublesn";
  inRange(1.5,3.5);
  inRange(1,3.5);
}

运行于ideone:

Pure cases
  inRange(1,3) -> Integral
  inRange(1.5,3.5) -> Real
Mixed int/unsigned
  inRange(1,3) -> Integral
  inRange(1,3) -> Integral
Mixed float/double
  inRange(1.5,3.5) -> Real
  inRange(1.5,3.5) -> Real
Mixed int/double
  inRange(1.5,3) -> Real
  inRange(1,3.5) -> Real
Mixed int/double,with more doubles
  inRange(1.5,3) -> Real
  inRange(1.5,3.5) -> Real
  inRange(1,3.5) -> Real

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读