引用类型的移除
c++11
标准库中提供了一个std::remove_reference
类模板,如果传递进来的模板参数是一个引用类型,则会把这个引用类型中的引用部分删除,先看一下用法:
#include <iostream>
template<class T1,class T2>
void print_is_same()
{
std::cout << "T1 类型为: " << typeid(T1).name() << std::endl;
std::cout << "T2 类型为: " << typeid(T2).name() << std::endl;
// 值为1 表示两个类型相等,值为0表示两个类型不等,is_same是标准库中用于判断两个类型是否相等
// 的类模板,写成std::is_same<T1,T2>::value效果也是一样。
// std::is_same<T1,T2>()这种写法产生了is_same<T1,T2>的临时对象,而且调用了该类模板的类型
// 转换运算符把对象转换为了一个整型值输出
std::cout << "T1 和 T2 类型是否相等: " << std::is_same<T1, T2>() << std::endl;
}
int main()
{
std::remove_reference<int>::type a;
std::remove_reference<int&>::type b;
std::remove_reference<int&&>::type c;
print_is_same<decltype(a), decltype(b)>();
print_is_same<decltype(a), decltype(c)>();
return 0;
}
我曾经也恬不知耻地认为很熟练C++
,说来可笑,来来来,小板凳,咋俩聊聊std::remove_reference
源码,哎,咋还没开始,你人跑了,哈哈哈哈(放松,娱乐一下)
另外,`C++14标准中通过别名模板技术定义了大量的别名,例如:
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
所以,前面代码中main()
函数里,就可以写的更简便了,可以省略::type
了
std::remove_reference_t<int> a;
std::remove_reference_t<int&> b;
std::remove_reference_t<int&&> c;
std::remove_reference
也是一个trait
类模板,想一想,如果要你自己实现一个类似功能,应该怎么写?
#include <iostream>
// 泛化版本
template<typename T>
struct RemoveReference
{
using type = T;
};
// 特化版本
template<typename T>
struct RemoveReference<T&>
{
using type = T;
};
template<typename T>
struct RemoveReference<T&&>
{
using type = T;
};
// 别名模板
template<typename T>
using RemoveReference_t = typename RemoveReference<T>::type;
int main()
{
int&& a2 = 12;
// 从报错的结果可以看出来b2的结果已经转成int类型
// 献上我的膝盖,炸裂啊这里,需要久久反思
//RemoveReference_t<decltype(a2)> b2 = "dd";
// 注释掉出错的上一行,运行下面的代码
RemoveReference_t<decltype(a2)> b2 = 125;
int i = 64;
int& c2 = i;
RemoveReference_t<decltype(c2)> d2 = 500;
std::cout << typeid(b2).name() << std::endl;
std::cout << typeid(d2).name() << std::endl;
return 0;
}
引用类型的增加
- 所谓引用类型的增加,其实就是根据给定的类型创建一个左值或右值引用。
c++11
标准库中提供了一个std::add_lvalue_reference
类模板,用于传入一个类型,返回该类型对应的左值引用类型。例如,传入一个int
类型,返回int&
类型。c++11
也提供了一个std::add_rvalue_reference
类模板,用于传入一个类型,返回该类型对应的右值引用类型,例如,传入一个int
类型,返回int&&
类型。- 相对应地,还有
std::is_lvalue_reference
和std::is_rvalue_reference
类模板,用于判断某个类型是否是左值引用还是右值引用类型。
#include <iostream>
int main()
{
int a = 15;
std::add_lvalue_reference<decltype(a)>::type b = a; // b的类型为int&
std::add_rvalue_reference<decltype(a)>::type c = 16; // c的类型为int&&
using btype = std::add_lvalue_reference_t<int>; // _t是别名模板
std::cout << std::is_same<int&, btype>() << std::endl; // 1
using ctype = std::add_rvalue_reference_t<int>;
std::cout << std::is_lvalue_reference<btype>::value << std::endl; // 1
std::cout << std::is_rvalue_reference<ctype>::value << std::endl; // 1
std::add_rvalue_reference_t<int&> cc1 = a; // cc1的类型为int&,这里涉及到引用折叠: &和&& 折叠得到&
std::add_rvalue_reference_t<int&&> cc2 = 16; // cc2的类型为int&&,这里涉及引用折叠,&和&& 折叠得到&&
return 0;
}
虽然目前没有用到过,但是感觉是个好东西。添加左值和右值引用类型
std::add_lvalue_reference
和std::add_rvalue_reference
同样都是trait类模板,如果自己来实现类似的功能,你会怎么写?
先写一个增加左值引用类型的类模板
#include <iostream>
template<typename T>
struct AddLValueReference
{
using type = T&;
};
// 实际上可以直接简化为using AddLValueReference_t = T&; 这样就不用定义AddLValueReference了
template<typename T>
using AddLValueReference_t = typename AddLValueReference<T>::type;
int main()
{
int anew = 15;
// decltype(anew)为int类型
// bnew为int&类型
AddLValueReference_t<decltype(anew)> bnew = anew;
int&& anew2 = 17;
// decltype(anew2)为int&&类型
// bnew2为int&类型,引用折叠:有左值引用,结果必然为左值引用,
AddLValueReference_t<decltype(anew2)> bnew2 = anew2;
return 0;
}
增加右值引用类型的trait
类模板如下:
#include <iostream>
template<typename T>
struct AddRValueReference
{
using type = T&&;
};
template<typename T>
// 实际上可以直接简化为using AddRValueReference_t = T&&;
// 这样就不要定义AddRValueReference了
using AddRValueReference_t = typename AddRValueReference<T>::type;
int main()
{
int argnew = 15;
// brgnew的类型为int&&
AddRValueReference_t<decltype(argnew)> brgnew = 18;
int&& argnew2 = 15;
// brgnew2的类型为int&&,根据引用折叠,两个右值引用遇到一起,结果还是右值引用
AddRValueReference_t<decltype(argnew2)> brgnew2 = 18;
int tmpvalue = 16;
int& argnew3 = tmpvalue;
// brgnew3的类型是int&
// 根据引用折叠规则,左值引用和右值引用遇到一起,结果还是左值引用
AddRValueReference_t<decltype(argnew3)> brgnew3 = tmpvalue;
return 0;
}