进入C++11时代,大部分流行的库都支持了C++11的新特性。C++11的新特性虽然有时候被诟病为语法糖,但是确实对开发很有助力,甚至有时候跟脚本语言的简洁度有的一拼了。其中自动模板推导是C++11的惊艳功能之一,如果仅仅知道auto和decltype是不够的。以下笔记均以vs2013为准。
首先auto功能已经广为人知,auto可以根据当前表达式自动推导出当前变量的类型。auto推导一般是不带有引用&的,所以最好手动加&,即auto &;auto倾向于不带有const,只有必要情况下才带有const,比如容器是const引用,不用const迭代器不行。如下是不行的:
auto i; i=10;
这说明auto不能根据无关的上下文来推导。函数返回值可以用auto,比如:
auto foo(int i, int j)->decltype(i + j)
{
return i + j;
}
auto f = [](int i, int j){return i + j; };
C++11的具名函数返回值判定需要->decltype语句,这使得函数非常难写难看,限制了使用范围;匿名函数却不需要。目前C++14可以不用写后面的->decltype,真正好用,不过普及还要一段时间。
decltype能获取已有变量模板。decltype是C++关键词,不是由其他模块组成的。如果使用旧版C++,可以使用boost库的typeof宏来自动推断类型。decltype的推断类型有一些问题,比如左值引用的数据,其模板推导带有引用&的,比如有如下代码,仅仅作为演示:
std::vector<int> vec = {1,2,3};
decltype<vec[0]> a = 10;//error!!
decltype<vec[0]> b;//error!!
编译器会报错,提示a,b都是左值引用。我只是想获取vector的模板,不需要引用啊?这时候有两种做法:
1、使用value_type,即
decltype(vec)::value_type a=10;
vetor的内部实现使用了type_traits技术,获取模板类型非常简单。
2、去引用:
typedef std::remove_reference<decltype(annotationList_)::reference>::type a = 10;
typedef std::remove_reference<decltype(annotationList_[0])>::type a = 10;
第一种方法使用vector内部type_traits技术提供的模板引用。两种方法使用了去引用功能,其内部实现很简单,因为模板匹配会把const、&、*分离出来:
template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };
按照这个想法,去除const和指针都是非常简单的事情,仅展示部分:
template<typename T> struct remove_pointer<T*> { typedef T type; };
template <class T> struct remove_const<const T> { typedef T type; };
template <class T> struct remove_const<const T[]> { typedef T type[]; };
template<typename T> struct remove_all { typedef T type; };
template<typename T> struct remove_all<T const&> { typedef typename remove_all<T>::type type; };
同理还有添加的功能:
template<typename T>
struct add_const_on_value_type{typedef const T type;};
template<class _Ty>
struct add_rvalue_reference{typedef _Ty&& type;};
但是不要想着这么高端就把添加const/&/*的功能也照上述方法写一遍,其实直接在推导好的纯净模板上面添加const/&/*就行了。
在实现上述功能的文件里面,还有一些有意思的模板编程方法:
- 比较两个变量模板是否相同需要定义两个模板函数,根据模板匹配来执行
template<typename T, typename U> struct is_same { enum { value = 0 }; };
template<typename T> struct is_same<T,T> { enum { value = 1 }; };
- 模板是否带有const:
template <typename T> struct is_const { enum { value = 0 }; };
template <typename T> struct is_const<T const> { enum { value = 1 };