读书频道 > 网站 > 网页设计 > 深入应用C++11:代码优化与工程级应用
1.2.2 模板的别名
15-07-07    下载编辑
收藏    我要投稿   
在StackOverflow的最近一次世界性调查中,C++11在所有的编程语言中排名第二, C++11受到程序员的追捧是毫不意外的,因为它就像C++之父Bjarne Stroustrup说的:它看起来就像一门新的语言。C++11新增加了相当多的立即去当当网订购

大家都知道,在C++中可以通过typedef重定义一个类型:

typedef unsigned int uint_t;

被重定义的类型名叫“typedef-name”。它并不是一个新的类型,仅仅只是原有的类型取了一个新的名字。因此,下面这样将不是合法的函数重载:

void func(unsigned int);

void func(uint_t);       // error: redef?inition

使用typedef重定义类型是很方便的,但它也有一些限制,比如,无法重定义一个模板。
想象下面这个场景:

typedef std::map<std::string, int> map_int_t;
// ...
typedef std::map<std::string, std::string> map_str_t;
// ...

我们需要的其实是一个固定以std::string为key的map,它可以映射到int或另一个std::string。然而这个简单的需求仅通过typedef却很难办到。

因此,在C++98/03中往往不得不这样写:

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

// ...

str_map<int>::type map1;

// ...

一个虽然简单但却略显烦琐的str_map外敷类是必要的。这明显让我们在复用某些泛型代码时非常难受。

现在,在C++11中终于出现了可以重定义一个模板的语法。请看下面的示例:

template <typename Val>
using str_map_t = std::map<std::string, Val>;
// ...
str_map_t<int> map1;

这里使用新的using别名语法定义了std::map的模板别名str_map_t。比起前面使用外敷模板加typedef构建的str_map,它完全就像是一个新的map类模板,因此,简洁了很多。

实际上,using的别名语法覆盖了typedef的全部功能。先来看看对普通类型的重定义示例,将这两种语法对比一下:

// 重定义unsigned int
typedef unsigned int uint_t;
using uint_t = unsigned int;

// 重定义std::map
typedef std::map<std::string, int> map_int_t;
using map_int_t = std::map<std::string, int>;

可以看到,在重定义普通类型上,两种使用方法的效果是等价的,唯一不同的是定义语法。

typedef的定义方法和变量的声明类似:像声明一个变量一样,声明一个重定义类型,之后在声明之前加上typedef即可。这种写法凸显了C/C++中的语法一致性,但有时却会增加代码的阅读难度。比如重定义一个函数指针时:

typedef void (*func_t)(int, int);

与之相比,using后面总是立即跟随新标识符(Identif?ier),之后使用类似赋值的语法,把现有的类型(type-id)赋给新类型:

using func_t = void (*)(int, int);

从上面的对比中可以发现,C++11的using别名语法比typedef更加清晰。因为typedef的别名语法本质上类似一种解方程的思路。而using语法通过赋值来定义别名,和我们平时的思考方式一致。

下面再通过一个对比示例,看看新的using语法是如何定义模板别名的。

/* C++98/03 */

template <typename T>
struct func_t
{
   typedef void (*type)(T, T);
};
// 使用 func_t 模板
func_t<int>::type xx_1;

/* C++11 */

template <typename T>
using func_t = void (*)(T, T);
// 使用 func_t 模板
func_t<int> xx_2;

从示例中可以看出,通过using定义模板别名的语法,只是在普通类型别名语法的基础上增加template的参数列表。使用using可以轻松地创建一个新的模板别名,而不需要像C++98/03那样使用烦琐的外敷模板。

需要注意的是,using语法和typedef一样,并不会创造新的类型。也就是说,上面示例中C++11的using写法只是typedef的等价物。虽然using重定义的func_t是一个模板,但func_t<int>定义的xx_2并不是一个由类模板实例化后的类,而是void(*)(int, int)的别名。

因此,下面这样写:

void foo(void (*func_call)(int, int));
void foo(func_t<int> func_call);  // error: redef?inition

同样是无法实现重载的,func_t<int>只是void(*)(int, int)类型的等价物。

细心的读者可以发现,using重定义的func_t是一个模板,但它既不是类模板也不是函数模板(函数模板实例化后是一个函数),而是一种新的模板形式:模板别名(alias template)。

其实,通过using可以轻松定义任意类型的模板表达方式。比如下面这样:

template <typename T>
using type_t = T;
// ...
type_t<int> i;

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

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:1.3 功能
下一篇:1.5 小结
相关文章
图文推荐
JavaScript网页动画设
1.9 响应式
1.8 登陆页式
1.7 主题式
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站