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. UI与数据的绑定

    核心是数据变化跟踪与UI更新的问题 概念整理: 供业务使用的叫数据: 供UI使用的叫状态: UI的变化能被监听到: 数据的变化能实时反映到UI上: 数据变化—>拦截—〉UI状态重置—>UI ...

  2. CF379C-New Year Ratings Change

    https://www.luogu.org/problemnew/show/CF379C 一道水题,折腾了我好久! 解题: 先排序,从小到大挨个满足客户,把最终rating放进集合里,判断是否已经给出 ...

  3. 洛谷 P1120 小木棍 题解

    每日一题 day54 打卡 Analysis 一,管理员已经在题目中告诉你输入时去掉长度大于50的木棍. 二,想好搜索什么.很明显我们要枚举把哪些棍子拼接成原来的长棍,而原始长度(原来的长棍的长度)都 ...

  4. 08_STP(数通华为)

    1. 网络拓扑 2. 激活生成树[SW1]stp mode stp [SW1]stp enable [SW2]stp mode stp [SW2]stp enable [SW3]stp mode st ...

  5. 通过patch 方式解决cube.js 集成cratedb 的问题

    今天有写过一个简单的cube.js 集成cratedb 的说明,主要是在driver 上的兼容问题,处理方法是删除不兼容的代码 实际上我们也可以通过类似linux c 开发中的patch 方式解决,简 ...

  6. Filters in ASP.NET Core

    Filters in ASP.NET Core allow code to be run before or after specific stages in the request processi ...

  7. REdis一致性方案探讨

    REdis功能强大众所周知,能够大幅简化开发和提供大并发高性能,但截止到REdis-5.0.5仍然存在如下几大问题: 一致性问题 这是由于REdis的主从复制采用的是异步复制,异常时可能发生主节点的数 ...

  8. A`>G?~C009

    A`>G?~C009 这场怎么才5题...看完猫的提交记录以为猫猫没写这场F A Multiple Array 直接做 B Tournament 直接树d C Division into Two ...

  9. Excel 截取字符,判断县区 城市。

    https://jingyan.baidu.com/article/624e7459aa90e434e8ba5a8a.html https://jingyan.baidu.com/article/9f ...

  10. JetBrains套装免费学生授权申请(IntelliJ, ReSharper, WebStorm...)

    IntelliJ作为一款强大的Java开发IDE,售价自然也不会低.但是对于学生或教师来说,JetBrains开发工具免费提供给学生和教师使用.而且取得一次授权后只需要使用相同的 JetBrains ...