C++11的模板类型判断——std::is_same和std::decay

问题提出:有一个模板函数,函数在处理int型和double型时需要进行特殊的处理,那么怎么在编译期知道传入的参数的数据类型是int型还是double型呢? 

如:

#include <iostream>
template<typename TYPE>
void typeCheck(TYPE data)
{
//do something check data type
//std::cout<< out put the type
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里就需要用到C++11的type_traits头文件了,type_traits头文件定义了很多类型检查相关的方法,上面的例子具体用到了其中两个结构:

std::is_same 判断类型是否一致

位于头文件<type_traits>

这个结构体作用很简单,就是两个一样的类型会返回true

bool isInt = std::is_same<int, int>::value; //为true
  • 1

下面是官方的例子:

#include <iostream>
#include <type_traits>
#include <cstdint> void print_separator()
{
std::cout << "-----\n";
} int main()
{
std::cout << std::boolalpha; std::cout << std::is_same<int, int32_t>::value << '\n'; // true
std::cout << std::is_same<int, int64_t>::value << '\n'; // false
std::cout << std::is_same<float, int32_t>::value << '\n'; // false print_separator(); std::cout << std::is_same<int, int>::value << "\n"; // true
std::cout << std::is_same<int, unsigned int>::value << "\n"; // false
std::cout << std::is_same<int, signed int>::value << "\n"; // true print_separator(); // unlike other types 'char' is not 'unsigned' and not 'signed'
std::cout << std::is_same<char, char>::value << "\n"; // true
std::cout << std::is_same<char, unsigned char>::value << "\n"; // false
std::cout << std::is_same<char, signed char>::value << "\n"; // false
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

通过std::is_same即可判断两个类型是否一样,特别在模板里面,在不清楚模板的参数时,此功能可以对一些特定的参数类型进行特殊的处理。

这里说个题外话,大家是否通过std::is_same发现,char既不是unsigned char也不是signed char,char就是char,这和int是signed int的缩写是不一样的,char的表达范围可能等同于signed char,也可能等同于unsigned char,取决于编译器,一般是等同于signed char,但这个仅仅是范围等同,就像32位上int和long范围是一样的,但不是同一个类型。

因为用途不同,char用于表达字符,理论上不应该关心其正负的实现,而signed char 和 unsigned char 用于表达数值,或可移植的char。

回到正文,std::is_same可以判断两种类似是否一样,那么用在模板里就是利器了,本位一开始提到的那个问题就可以这样写:

#include <iostream>
template<typename TYPE>
typeCheck(TYPE data)
{
if(std::is_same<TYPE,int>::value)
{
std::cout<<"int type";
//do something int
}
else
{
//.........
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

视乎很美好,再看一个示例:

// is_same example
#include <iostream>
#include <type_traits>
#include <cstdint> typedef int integer_type;
struct A { int x,y; };
struct B { int x,y; };
typedef A C; int main() {
std::cout << std::boolalpha;
std::cout << "is_same:" << std::endl;
std::cout << "int, const int: " << std::is_same<int, const int>::value << std::endl;//false
std::cout << "int, int&: " << std::is_same<int, int&>::value << std::endl;//false
std::cout << "int, const int&: " << std::is_same<int, const int&>::value << std::endl;//false
std::cout << "int, integer_type: " << std::is_same<int, integer_type>::value << std::endl;//true
std::cout << "A, B: " << std::is_same<A,B>::value << std::endl;//false
std::cout << "A, C: " << std::is_same<A,C>::value << std::endl;//true
std::cout << "signed char, std::int8_t: " << std::is_same<signed char,std::int8_t>::value << std::endl;//true
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

输出:

is_same:
int, const int: false
int, int&: false
int, const int&: false
int, integer_type: true
A, B: false
A, C: true
signed char, std::int8_t: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

发现std::is_same的判断是很严格的 

但是有时候在编辑模板的时候又发现用std::is_same的判断太过严格,还是之前的例子:

#include <stdlib.h>
#include <iostream>
#include <type_traits> template<typename TYPE>
void typeCheck(TYPE data); int _tmain(int argc, _TCHAR* argv[])
{
int a = 1;
const int& b = a;
int& c = a;
int d[12];
const int& e = d[7];
typeCheck(a);//int type
typeCheck(b);//int type
typeCheck(c);//int type
typeCheck(d[7]);//int type
typeCheck(e);//int type
typeCheck(8);//int type
system("pause");
return 0;
} template<typename TYPE>
void typeCheck(TYPE data)
{
if(std::is_same<TYPE,int>::value)
{
std::cout<<"int type"<<std::endl;
}
else if(std::is_same<TYPE,std::string>::value)
{
std::cout<<"string type"<<std::endl;
}
else
{
std::cout<<"other type";
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

输出:

int type
int type
int type
int type
int type
int type
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

测试后发现,虽然变量b,c使用引用,但std::is_same还是能识别出来的,但是!! 

如果我显示的指定模板参数类型时情况有不一样了:

#include <stdlib.h>
#include <iostream>
#include <type_traits> template<typename TYPE>
void typeCheck(TYPE data); int _tmain(int argc, _TCHAR* argv[])
{
int a = 1;
const int& b = a;
int& c = a;
int d[12]; typeCheck<int>(a); //int type
typeCheck<const int&>(b);//other type
typeCheck<int &>(c); //other type
typeCheck<const int&>(d[7]);//other type
typeCheck(8); //int type
system("pause");
return 0;
} template<typename TYPE>
void typeCheck(TYPE data)
{
if(std::is_same<TYPE,int>::value)
{
std::cout<<"int type"<<std::endl;
}
else if(std::is_same<TYPE,std::string>::value)
{
std::cout<<"string type"<<std::endl;
}
else
{
std::cout<<"other type";
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

输出:

int type
other type
other type
other type
int type
  • 1
  • 2
  • 3
  • 4
  • 5

瞬间结果就不一样了,这很好了解,从上面可知道,std::is_same对int和const int\int &\const int&等都是区别对待的,但在写模板函数时,经常会强制指定常引用进行传参,以免进行数据拷贝,这时候is_same就做出了不相等的判断,但是有时候其实我们还是希望TYPE和const
TYPE& 是能认为是一样的,这时就需要std::decay进行退化处理

std::decay 退化类型的修饰

std::decay就是对一个类型进行退化处理,他的实现如下:

template< class T >
struct decay {
private:
typedef typename std::remove_reference<T>::type U;
public:
typedef typename std::conditional<
std::is_array<U>::value,
typename std::remove_extent<U>::type*,
typename std::conditional<
std::is_function<U>::value,
typename std::add_pointer<U>::type,
typename std::remove_cv<U>::type
>::type
>::type type;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

看着比较抽象,其实就是把各种引用啊什么的修饰去掉,把cosnt int&退化为int,这样就能通过std::is_same正确识别出加了引用的类型了 

上面的例子改为:

#include "stdafx.h"
#include <stdlib.h> #include <iostream>
#include <type_traits> template<typename TYPE>
void typeCheck(TYPE data); int _tmain(int argc, _TCHAR* argv[])
{
int a = 1;
const int& b = a;
int& c = a;
int d[12]; typeCheck<int>(a);//int type
typeCheck<const int&>(b);//int type
typeCheck<int &>(c);//int type
typeCheck<const int&>(d[7]);//int type
typeCheck(8);//int type
system("pause");
return 0;
} template<typename TYPE>
void typeCheck(TYPE data)
{
if(std::is_same<typename std::decay<TYPE>::type,int>::value)
{
std::cout<<"int type"<<std::endl;
}
else
{
std::cout<<"other type"<<std::endl;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

在cppref有个更加详细的例子:

#include <iostream>
#include <type_traits> template <typename T, typename U>
struct decay_equiv :
std::is_same<typename std::decay<T>::type, U>::type
{}; int main()
{
std::cout << std::boolalpha
<< decay_equiv<int, int>::value << '\n'
<< decay_equiv<int&, int>::value << '\n'
<< decay_equiv<int&&, int>::value << '\n'
<< decay_equiv<const int&, int>::value << '\n'
<< decay_equiv<int[2], int*>::value << '\n'
<< decay_equiv<int(int), int(*)(int)>::value << '\n';
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

输出:

true
true
true
true
true
true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

总结:

  • 在模板里可以通过std::is_same判断模板的类型,从而实现对不同类型的区别对待
  • 在堆类型要求不是非常严格的情况下,可以使用std::decay把类型退化为基本形态,结合std::is_same用,可以判断出更多的情况

【C/C++开发】C++11的模板类型判断——std::is_same和std::decay的更多相关文章

  1. c++11 template 模板练习

    直接上代码吧 to do // 111111.cpp: 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> ...

  2. c++11::std::is_same/decay

    #include <type_traits> std::is_same 判断类型是否一致 通过std::is_same即可判断两个类型是否一样,特别在模板里面,在不清楚模板的参数时,此功能 ...

  3. Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构

    分享两篇Win 10应用开发的XML文档结构:Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构. Win 10 开发中Adapt ...

  4. Windows Phone 8初学者开发—第11部分:设置SounBoard应用程序

    原文 Windows Phone 8初学者开发—第11部分:设置SounBoard应用程序 原文地址: http://channel9.msdn.com/Series/Windows-Phone-8- ...

  5. Effective Modern C++翻译(2)-条款1:明白模板类型推导

    第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltype,接着C++14扩展了auto和dec ...

  6. MS CRM 2011的自定义和开发(11)——插件(plugin)开发(二)

    http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2339490.html MS CRM 2011的自定义和开发(11)——插件(plugin ...

  7. ASP.NET自定义控件组件开发 第五章 模板控件开发

    原文:ASP.NET自定义控件组件开发 第五章 模板控件开发 第五章 模板控件开发 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接 ...

  8. 现代C++之理解模板类型推断(template type deduction)

    理解模板类型推断(template type deduction) 我们往往不能理解一个复杂的系统是如何运作的,但是却知道这个系统能够做什么.C++的模板类型推断便是如此,把参数传递到模板函数往往能让 ...

  9. 11 Zabbix Item类型之Zabbix Calculated 计算型Item类型

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 11 Zabbix Item类型之Zabbix Calculated 计算型Item类型 计算类型 ...

随机推荐

  1. oracle之随机数

    一.首先创建一个测试表 select * from DIM_IA_TEST1 生成随机数 select t.*,rownum rn from  (select * from DIM_IA_TEST1 ...

  2. combineReducers(reducers)

    combineReducers(reducers) 随着应用变得越来越复杂,可以考虑将 reducer 函数 拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分. combine ...

  3. Spring @Scheduled定时任务的fixedRate,fixedDelay,cron的作用和不同

    一.   三种定时类型. 1.cron  --@Scheduled(cron="0/5 * * * *?") 当时间达到设置的时间会触发事件.上面那个例子会每5秒执行一次. 201 ...

  4. 学习:Windows API核心DLL文件

    在 Windows 的系统目录中,存在着很多的动态链接库文件(DLL 文件).这些 DLL 文件中包括了 Windows API 函数可执行程序. DLL 将各函数"导出",这样应 ...

  5. (3)使用Android手机作为树莓派的屏幕

    https://jingyan.baidu.com/album/676629977483b154d51b848e.html

  6. css实现步骤条(未封装组件)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. haproxy 2.0 dataplaneapi rest api 试用

    我们可以基于haproxy 提供的dataplaneapi 动态进行haproxy 配置的修改,增强haproxy的可编程能力,以下是一个简单 的测试,基于docker-compose运行 环境准备 ...

  8. Django 基础篇(一)

    创建虚拟环境 创建:mkvirtualenv [虚拟环境名称] 删除:rmvirtualenv [虚拟环境名称] 进入:workon [虚拟环境名称] 退出:deactivate 所有的虚拟环境,都位 ...

  9. Spring Could Feign 设计原理

    什么是Feign? Feign 的英文表意为"假装,伪装,变形", 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HT ...

  10. PKUSC2019滚粗记

    PKUSC2019滚粗记 Day -INF 在\(\text{APIO}\)时得知省选考崩的自己居然能参加\(\text{SC}\),真是非常意外啊. Day 0 上午机房充斥着放假的气息,居然还成功 ...