C判定类型A是否能够基于隐式类型转换转为B类型?
原文见 C++ 有哪些鲜为人知的奇特操作? - 知乎,直接看代码:// 自定义两个内存大小不一样的类型,作为"布尔值" typedef char __True; typedef struct { char _[2]; } __False; template class IsCastable { private: // 稻草人函数 static A __A(); // 两个同名函数 __Test,入参分别是 B 和可变参数,返回值和入参不同 static __True __Test(B); // 函数 1 static __False __Test(...); // 函数 2 public: static constexpr bool Value = sizeof(__Test(__A())) == sizeof(__True); }; int main() { std::cout << IsCastable::Value << std::endl; // int 到 double,能够进行隐式类型转换,调用了函数1,返回 true std::cout << IsCastable::Value << std::endl; // int 到 string 不能够进行隐式类型转换,调用了函数2,返回 false }
解释如下:
1. 上述 IsCastable 类中首先声明了一个"稻草人函数"(无函数体),唯一的作用是获得一个 A 类型的值给 sizeof 看。 有人会问,为什么不直接使用形如"T()"这样的写法呢?很显然,因为并不是所有的 T 都具有默认构造函数,而如果 T 没有默认构造函数,那么"T()"就是错误的。
2. 上述 IsCastable 类中声明了一对重载函数(__Test),这两个函数的区别有二:返回值不同,一个是 sizeof 的结果为 1 的值,而另一个是 sizeof 的结果为 2 的值形参不同,一个是 B,一个是"..." ,也就是说,如果我们给这一对重载函数传入一个 A 类型的值时,由于"..."参数的重载确定优先级低于其他一切可行的重载版本,只要 A 到 B 的隐式类型转换能够发生,重载确定的结果就一定是调用第一个版本的函数,返回值为__True;否则,只有当 A到 B 的隐式类型转换真的不可行时,编译器才会"被迫"选择那个编译器"最不喜欢的版本",从而使得返回值为__False。返回值的不同,就能够直接体现在 sizeof 的结果不同上。所以,只需要判定sizeof(__Test(__A()))是多少,就能够达到我们最终的目的了。