1、  右尖括号

  我们在C++98/03中使用泛型编程的时候,经常遇到“>>”被当作右移操作符,而不是模板参数的结尾。假如我们有如下代码:

template <typename T>
class Foo{}; void func(void)
{
vector<Foo<int>> test;
}

  使用C++98/03的时候会出现如下错误:

hello.c::: error: ‘>>’ should be ‘> >’ within a nested template argument list
vector<Foo<int>> test;

  意思就是vector<Foo<int>>的写法不支持,我们不得不改成vector<Foo<int> >,”>>”之间有个空格。在C++11中对”>>”做了单独处理,是编译器知道“>>”是一个右移操作符还是模板结束符。不过,也有特例。如下代码在C++11中就会报错:

template <int T>
class Foo{}; void func(void)
{
vector<Foo< >> >> test;
}

  报错内容为:

hello.c::: error: expected unqualified-id before numeric constant
vector<Foo< >> >> test;

  也就是产生了二义性,那么如何解决呢?加上括号就OK。

vector<Foo<( >> )>> test;

2、  模板别名

  在c++98/03中,我们可以通过typedef来定义一个类型的别名,当然,并不是产生新的类型,而是一个别名而已。像这样:

typedef unsigned int uint;

  因为是别名,所以并不能通过typedef来进行函数的重载,像这样:

typedef unsigned int uint;
void func(unsigned int);
void func(uint); //error:erdefinition

  那么我们假如有如下需求,我们看C++98/03是怎么实现的:

  我们需要一个map,固定的key值为string,value为string或者int。

  正常定义是两种类型:

typedef map<string, int> map_s_i;
typedef map<string, string> map_s_s;

  那如果我们用模板来解决呢?

template <typename Val>
struct str_map
{
typedef map<string, Val> type;
};
str_map<int>::type map1;

  好,现在有了C++11,我们来看C++11是怎么实现的:

template <typename Val>
using str_map_t = map<string, Val>; str_map_t<int> map1;

  是不是很简单?语法也比C++98/03要简单太多,代码也简洁了不少。

  这里我们使用了C++11的关键字using,using几乎涵盖了typedef的所有功能。typedef的定定义方法和变量的声明类似,就像声明一个变量,在变量之前加上重定义类型,然后加上typedef即可;而using则不一样,using后面接新标识符,而后像赋值一样将需要别名的类型赋值给新标识符即可。总的来说,typedef有时候阅读难度比using更大(比如在定义函数指针的时候),using别名语法比typedef更加清晰。

//重定义unsigned int
typedef unsigned int uint_t;
using uint_u = unsigned int; //重定义map
typedef map<string, int> map_s_i_t;
using map_s_i_u = map<string, int>; //定义函数指针
typedef void (*func_t)(int, int);
using func_u = void(*)(int, int);

  需要注意的是,using也不会产生新类型,上面的例子中using只是typedef的等价物,目的是改善C++98/03含蓄的语法,使代码可读性更高,更简洁。using同样不能重定义函数:

using uint = unsigned int;
void func(unsigned int);
void func(uint); //error:erdefinition

  值得注意的是,using定义的模板,既不是类模板,也不是函数模板,而是一种新的模板表达方式:模板别名。通过using可以轻松定义任意类型的模板表达方式。

template<typename T>
using u_t = T; u_t<int> i_int;

  u_t实例化后的类型和它的模板参数类型等价,这里u_t<int>等价于int。

3、  函数模板的默认模板参数

3.1 C++11的默认参数

  c++98/03中,类模版可以有默认模板参数,但是函数模板不支持默认参数。

template<typename T, typename U = int, U N = >
struct Foo
{
//
} template <typename T = int> //error in c++98/03:default template arguments
void func()
{
//
}

  但是在C++11中解除了这个限制,上面的函数可以直接调用,就像调用正常函数一样:

int main(void)
{
func(); return ;
}

  当所有的类型都有默认的参数外,函数的调用就像一般的函数调用一样,但是类模板即使所有的类型都有参数,还是需要加上”<>”来实例化。

3.2 细节

  模版默认参数可以和自动推导结合使用来提升灵活性。我们可以在平时的编码中,指定一部分模板参数,另外的一部分自动推导,但是有两条规则:

  如果编译器无法自动推导函数模板参数类型,则使用默认模板参数;

  如果能推导函数模板参数,则使用推导类型。

  我们来看两个例子:

template<typename T>
struct identity
{
typedef T type;
}; template <typename T = int>
void func(typename identity<T>::type va, T = )
{
//...
} int tfunc(void)
{
func(); //T->int
func(, 123.0); //T->double return ;
}

  通过identity模板禁用了val的类型自动推导,但是func指定了模板参数T的默认参数类型,所以func(123)使用默认的int类型,而在func(123,123.0)中,第二个参数123.0为double类型,所以T优先被推导为double类型。

C11简洁之道:模板改进的更多相关文章

  1. C11简洁之道:初始化改进

    1.  C++98/03初始化 我们先来总结一下C++98/03的各种不同的初始化情况: //普通数组 ] = {, , }; //POD(plain old data) struct A { int ...

  2. C11简洁之道:类型推导

    1.  概述 C++11里面引入了auto和decltype关键字来实现类型推导,通过这两个关键字不仅能方便的获取复杂的类型,还能简化书写,提高编码效率. 2.  auto 2.1 auto关键字的新 ...

  3. C11简洁之道:tupe元祖

    tuple元组是一个固定大小不同类型的值的集合,是泛化的std::pair.我们也可以把它当作一个通用的结构体来使用,不需要创建结构体有获取结构体特征,在某些情况可以取代结构体,使程序更简洁.直观. ...

  4. C11简洁之道:lambda表达式

    1.  定义 lambda表达式是C++11非常重要也是很常用的特性之一,来源于函数式编程的概念,也是现代编程语言的一个特点.它有如下特点: 声明式编程风格:就地匿名定义目标函数或者函数,不需要额外写 ...

  5. C11简洁之道:函数绑定

    1.  可调用对象 在C++中,有“可调用对象”这么个概念,那么什么是调用对象呢?有哪些情况?我们来看看: 函数指针: 具有operator()成员函数的类对象(仿函数): 可以被转换为函数指针的类对 ...

  6. C11简洁之道:循环的改善

    1.  for循环的新用法 在C++98/03中,通过for循环对一个容器进行遍历,一般有两种方法,常规的for循环,或者使用<algorithm>中的for_each方法. for循环遍 ...

  7. 《Clean Code》 代码简洁之道

    作者介绍 原文作者: Robert C. Martin, Object Mentor公司总裁,面向对象设计.模式.UML.敏捷方法学和极限编程领域的资深顾问,是<敏捷软件开发:原则.模式.与实践 ...

  8. JavaScript 代码简洁之道

    摘要: 可以说是<Clean Code>的JS代码示例了,值得参考. 原文:JavaScript 代码简洁之道 作者:缪宇 Fundebug经授权转载,版权归原作者所有. 测试代码质量的唯 ...

  9. 30余套系统模版|DIV+CSS网页模板|简洁大气系统模板

    30余套系统模版|DIV+CSS网页模板|简洁大气系统模板.都是一些后台系统的模版,很适合开发一些管理系统,办公系统,网站后台系统等.使用很广泛,很实用的系统模版. 下载地址: 点击下载

随机推荐

  1. Phpcms V9导航循环下拉菜单的调用技巧

    这个方法基于PC V9官方模版中的调用方法,然后利用后台的“Phpcms V9菜单是否显示设置”控制菜单是否显示出来. 先看看最后的效果: 调用方法: <div id="navbar& ...

  2. 第十九次ScrumMeeting会议

    第十九次Scrum Meeting 时间:2017/12/9 地点:三公寓大厅 人员:蔡帜 王子铭 游心 解小锐 王辰昱 李金奇 杨森 陈鑫 赵晓宇 照片: 目前工作进展 名字 今日 明天的工作 蔡帜 ...

  3. ACM 第七天

    水题 B - Minimum’s Revenge There is a graph of n vertices which are indexed from 1 to n. For any pair ...

  4. LintCode-174.删除链表中倒数第n个节点

    删除链表中倒数第n个节点 给定一个链表,删除链表中倒数第n个节点,返回链表的头节点. 注意事项 链表中的节点个数大于等于n 样例 给出链表 1->2->3->4->5-> ...

  5. Swift-闭包理解(二)

    简明扼要的闭包表达式 其实Swift已经为我们提供了很多简化的语法,可以让我们保证代码的高可读性和维护性.还用上面的例子来说明,对于  greetPeople 这个全局函数来说,其实只需要使用一次,所 ...

  6. TCP系列29—窗口管理&流控—3、Nagle算法

    一.Nagle算法概述 之前我们介绍过,有一些交互式应用会传递大量的小包(称呼为tinygrams),这些小包的负载可能只有几个bytes,但是TCP和IP的基本头就有40bytes,如果大量传递这种 ...

  7. java 基础 --int 和Integer的区别

    感到脸红:int是整形 -128~127 Integer是正整型,你怎么会想到这样的回答,妈的,有脑子吗?!!! 1,int是基本数据类型,初始为0,Integer为封装类,初始为null ①无论如何 ...

  8. Git 应用补丁报错 “sha1 information is lacking or useless”

    因为现场代码在客户局域网内,不能连接到公司网络,所以一般更新的时候都是打补丁, 然后在客户现场应用补丁,但是最近在应用补丁的时候出现了如下问题: ... fatal: sha1 information ...

  9. 第33天:封装自己的class类

    封装自己的class类,实现浏览器兼容. <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  10. javabean 参数收集 设置属性 设置不同级别的域对象的属性 默认存储在pagecontext中

    javabean 参数收集  设置属性 设置不同级别的域对象的属性  默认存储在pagecontext中