参数列表中的C隐式类型转换
关于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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |