C++11使用using定义别名(替代typedef)

本文介绍了C++11中using关键字如何简化模板别名的定义,对比了typedef与using在重定义类型和模板上的差异,展示了如何通过using创建更易复用的str_map模板。

转自:http://c.biancheng.net/view/3730.html

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

typedef unsigned int uint_t;

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

void func(unsigned int);
void func(uint_t);  // error: redefinition

使用 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 后面总是立即跟随新标识符(Identifier),之后使用类似赋值的语法,把现有的类型(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 定义的 xx_2 并不是一个由类模板实例化后的类,而是 void(*)(int, int) 的别名。

因此,下面这样写:

void foo(void (*func_call)(int, int));
void foo(func_t<int> func_call);  // error: redefinition

同样是无法实现重载的,func_t 只是 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。

C++ 中,`typedef` 是一种用于定义数据类型别名的关键字,它并没有创建新的数据类型,而是为现有类型提供了一个更简洁或更具可读性的名称。这种方法可以简化复杂类型的声明,并增强代码的可读性。 ### 基本数据类型的别名定义 可以使用 `typedef` 为基本数据类型定义别名。例如,可以将 `unsigned int` 类型定义为 `uint`: ```cpp typedef unsigned int uint; ``` 定义完成后,可以像使用原始类型一样使用别名: ```cpp uint a = 10; ``` ### 结构体的别名定义 `typedef` 还常用于为结构体定义别名。例如,定义一个结构体并为其创建别名: ```cpp typedef struct { int x; int y; } Point; ``` 现在可以直接使用 `Point` 来声明变量: ```cpp Point p1; ``` ### 复合类型的别名定义 `typedef` 可以结合指针、数组等复合类型使用。例如,定义一个指向整数的指针类型的别名: ```cpp typedef int* IntPtr; ``` 然后可以使用别名声明指针变量: ```cpp IntPtr ptr; ``` ### 函数指针的别名定义 `typedef` 在定义函数指针类型时非常有用。例如,定义一个指向返回 `int` 且无参数的函数的指针类型的别名: ```cpp typedef int (*FuncPtr)(); ``` 定义完成后,可以轻松声明该类型的指针变量: ```cpp FuncPtr myFuncPtr; ``` 结合实际函数使用时,可以将函数地址赋值给指针并调用: ```cpp int myFunction() { return 42; } myFuncPtr = &myFunction; int result = myFuncPtr(); // 调用 myFunction ``` ### 使用 typedef 的注意事项 - **作用域**:`typedef` 定义的类型别名作用域仅限于其定义的位置。如果定义在函数内部,则只能在该函数内部使用。 - **C++11替代方法**:C++11 引入了 `using` 关键字来定义类型别名,其语法更直观。例如: ```cpp using MyInt = int; ``` - **与类和结构体结合**:`typedef` 可以用于类和结构体的定义中,但需要注意其与类作用域的关系[^3]。 ### 示例代码 以下是一个完整的示例,展示 `typedef` 在结构体和函数指针中的应用: ```cpp #include <iostream> // 定义结构体别名 typedef struct { int x; int y; } Point; // 定义函数指针别名 typedef int (*MathFunc)(int, int); // 示例函数 int add(int a, int b) { return a + b; } int main() { Point p = {10, 20}; std::cout << "Point: (" << p.x << ", " << p.y << ")" << std::endl; MathFunc func = add; int result = func(5, 3); std::cout << "Result of add: " << result << std::endl; return 0; } ``` 通过 `typedef`,可以显著提高代码的可读性和可维护性,特别是在处理复杂类型时。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值