本文还是模板元的入门篇,上一篇文章讲了基础的语法(参见我的专栏),这里讲一下模板元中常用的两个关键字,typeid和decltype。题外话,CPP中做函数常用的关键字,不算模板元的话,比较特殊的就算sizeof了,C真是惜字如金啊。但是为了模板元的特性,CPP竟然一下子推出两个关键字,看来确实有够重视,有够有难度。
KEYW:Typeid
typeid
运算符是在 C++98 标准中就已经引入的关键字,它用于在运行时获取一个表达式的类型信息,通常与 std::type_info
类一起使用,后者可以通过 typeid
运算符返回的结果进行查询。(关键字是不能通过语法实现的,因为它本身是语法的一部分)
#include <iostream>
#include <typeinfo>
int main() {
int myInt = 5;
double myDouble = 3.14;
const std::type_info& intType = typeid(myInt);
const std::type_info& doubleType = typeid(myDouble);
std::cout << "myInt is of type: " << intType.name() << std::endl;
std::cout << "myDouble is of type: " << doubleType.name() << std::endl;
return 0;
}
将type_info作为成员
std::type_info
对象的赋值操作并不像普通的数据类型那样直接。因此,你需要使用构造函数初始化列表来正确初始化 itemname
成员。
template <class T>
struct mexp
{
T item;
const std::type_info& itemname;
mexp(const T& val)
: item(val), itemname(typeid(val)) // 使用初始化列表
{
}
};
int main()
{
mexp<int> expint(14);
cout << expint.item << endl;
cout << expint.itemname.name() << endl;
}
const std::type_info& itemname;这个句子声明itemname是一个 引用类型,
怎么保证引用的对象不会被注销的
typeid(val)
的生命周期:typeid(val)
返回的std::type_info
对象是静态存储期的,即它在程序运行期间始终存在。这确保了itemname
引用的是一个有效的对象。- 构造函数内初始化:
itemname
在构造函数的初始化列表中被初始化为typeid(val)
,这个引用在mexp
对象的整个生命周期内都是有效的,因为typeid(val)
的返回对象是静态的。
KEYW:decltype
decltype是CPP11引入的关键字,用于推导表达式的类型。值得指出的是,它不会去计算表达式,只是去计算类型并且返回
使用方法如下
int i = 4;
decltype(i) a; //推导结果为int。a的类型为int。
using size_t = decltype(sizeof(0));//sizeof(a)的返回值为size_t类型
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
vector<int >vec;
typedef decltype(vec.begin()) vectype;
for (vectype i = vec.begin; i != vec.end(); i++)
{
//...
}
重用匿名类型
在C++中,我们有时候会遇上一些匿名类型,如:
struct
{
int d ;
doubel b;
}anon_s;
而借助decltype,我们可以重新使用这个匿名的结构体:
decltype(anon_s) as ;//定义了一个上面匿名的结构体
追踪函数的返回值类型
泛型编程中结合auto,用于追踪函数的返回值类型.这也是decltype最大的用途了。
template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
//这个写法->是显式的指明auto的类型
{
return x*y;
}
逗号运算搭建匹配空间
匹配空间是我自己在记笔记的时候用的名词(感觉还是挺贴合实际意思的),大家可以参考一下。我们使用SFINAE的时候,总是希望能够多来一些可以匹配的空位,让我们可以提出期望,一般来说,
- 有模板列表(名称依赖技术)
- 对模板实参列表中,有偏特化和具体化(全特化)技术
- 对模板函数,有返回值,和参数列表,还有函数体可以供操作
- 对类模板,有助手嵌套类+绑定,你还可以写模板函数,这很棒
但是,这些空间总是有限的,所以我们需要搭建匹配空间。下面是逗号匹配空间,在技巧总结中,还有第二种匹配空间
struct MyType {
int foo();
};
template <typename T>
auto check_foo(int) -> decltype(std::declval<T>().foo(), std::true_type());
template <typename T>
auto check_foo(...) -> std::false_type;