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. React Core Features

    React Core Features Here is a summary of the core features. We will cover each feature in detail thr ...

  2. LeetCode 490. The Maze

    原题链接在这里:https://leetcode.com/problems/the-maze/ 题目: There is a ball in a maze with empty spaces and ...

  3. [转载] miller rabin

    本文转载自https://www.cnblogs.com/zsq259/p/11602175.html Miller-Rabin 事先声明,因为菜鸡Hastin知识水平有限就是菜,因此语言可能不是特别 ...

  4. Python I/O编程 --读写文件、StringIO/ BytesIO

    I/O编程 Input/Output  输入/输出 Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水 Input Stream就是数据从外面(磁盘.网络)流进内存,Ou ...

  5. JS的ES5的扩展内容

    JS的ES5 1.严格模式: (1)什么是严格模式: 在全局或函数的第一条语句定义为:  'use strict' 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用 (2)严格模式作用: ...

  6. K8s的存储卷使用总结

    K8s的存储卷: 它有四种存储卷: 1. emptyDir: 空目录,这种存储卷会随着Pod的删除而被清空,它一般作为缓存目录使用,或临时目录, 当做缓存目录时,通常会将一块内存空间映射到该目录上,让 ...

  7. 组件&Props

    组件允许你将Ui拆分为独立可复用的代码片段,并对每个片段进行独立构思.本指南只在介绍组件的相关概念.你可以参考详细组件 API. 组件,从概念上类似与JavaScript函数.它接受任意的入参(既“p ...

  8. Windows开机自启动快捷操作

    1.对于没有自启动选项的软件,可以生成快捷方式,然后把快捷方式拖到启动文件夹里 2.查看是否拖入生效,可以在运行中输入 msconfig 3.点击确定 进入页面如下图 4.在此选项卡中上方有很多选项 ...

  9. Ubuntu 19.04 国内更新源

    2019年4月18日, Ubuntu 19.04 正式发布. Ubuntu 19.04 的 Codename 是"disco(迪斯科舞厅)": zkf@ubuntu:~$ lsb_ ...

  10. CentOS7下将Python的版本升级为3.7

    众所周知,在2020年python官方将不再支持2.7版本的python,所以使用3.x版本的python是必要的,但是linux中默认安装的python一般是2.6和2.7版本的,要是使用linux ...