我们有时为了实现某些逻辑,可能需要在编译时判定某两个类型是否相同,因此从C++11起,C++标准库提供了 std::is_same<T1, T2> 这个结构体方便我们进行查询。我们可以看以下示例代码:
#include <cstdio>
#include <type_traits>
extern "C" void CPPTest()
{
bool res = std::is_same<decltype(0), int>::value;
// C++中,整数字面量的默认类型即为int,
// 所以这里输出:res = 1
printf("res = %d\n", res);
res = std::is_same<decltype('c'), int>::value;
// C++中,字符字面量默认为char类型,所以这里与int不是同一种类型,
// 因此这里输出:res = 0
printf("res = %d\n", res);
}
这里需要注意的是,std::is_same 位于 <type_traits> 头文件中,对于有些编译器隐式引入该头文件,而有些则不会。因此为了跨平台兼容性,我们需要使用 std::is_same 的时候最好显式包含此头文件。
std::is_same的实现原理
而 std::is_same 的实现机制其实也不复杂,其核心原理是通过定义带有两个模板参数的函数或变量与带有一个模板参数的同名函数或变量,在实例化时,由编译器选择是实例化带有两个模板参数的版本还是带有一个模板参数的版本。如果选择的是带有两个模板参数的版本就说明,这两个类型是不相同的;反之,如果选择一个模板参数的版本,就说明这两个类型是相同的。我们可以看以下代码:
#include <cstdio>
template <typename T1, typename T2>
static inline constexpr bool IsSame(T1 t1, T2 t2)
{
return false;
}
template <typename T>
static inline constexpr bool IsSame(T t1, T t2)
{
return true;
}
extern "C" void CPPTest()
{
bool res = IsSame(0, int(0));
// 输出:res = 1
printf("res = %d\n", res);
res = IsSame('c', int(0));
// 输出:res = 0
printf("res = %d\n", res);
}
使用C11的generic selection
对于clang++编译器,它扩展了C11标准中的generic selection语法特性,因此在根据类型而选择不同表达式这一方面非常方便。我们看以下代码:
#include <cstdio>
extern "C" void CPPTest()
{
int i = _Generic('c', int:-1, char:1, default:0);
// 由于'c'的类型在C++中为char,
// 所以这里输出:i = 1
printf("i = %d\n", i);
}
注意,上述代码只能在Clang或Apple LLVM编译器上正常编译。当然,我们可以用 std::is_same 来作等价替换。见以下代码:
#include <cstdio>
#include <type_traits>
extern "C" void CPPTest()
{
int i = []() -> int {
using type_c = decltype('c');
if constexpr (std::is_same<type_c, int>::value) {
return -1;
}
if constexpr (std::is_same<type_c, char>::value) {
return 1;
}
return 0;
}();
// 输出:i = 1
printf("i = %d\n", i);
}
我们可以看到,generic selection在处理这种根据类型而选择不同表达式的表达上更为精简~[呲牙]
本文暂时没有评论,来添加一个吧(●'◡'●)