0xAA55 发表于 2022-2-15 12:00:37

【翻译】【C++】现代C艹中的using与typedef

# 现代C++中的`using`与`typedef`

原文:https://www.internalpointers.com/post/differences-between-using-and-typedef-modern-c
译者:(https://www.0xaa55.com/?1)

*清爽的类型别名定义方式*

## 为何使用类型别名

从初学C语言的时候,我们就已经掌握了通过给变量类型起别名的方式来避免代码变得过于复杂或者意义不明。简而言之,你可以给一个现有的变量类型(比如`int`)取一个新的名字(比如`Pixel`)。类型别名可用于帮助你书写清爽、干净且易于阅读的代码。

假设你正在弄一个图形库,请观察以下两个函数的差异。

        int getScreenWidth();

或者:

        Pixel getScreenWidth();

后者显然更直观,在声明了别名`Pixel`后,它返回的数值是干什么的就一目了然了。
另一个例子如下:

        std::map<std::string, std::vector<std::string>> map;

或者:

        Map map;

需要注意使用类型别名并不意味着创建新的类型。它只是以同义词的方式来指代原有的类型名。上文的`Pixel`依然是个`int`,且`Map`依然是鬼畜的`std::map<std::string, std::vector<std::string>>`,可以被用在只接受`int`或者`std::map<std::string, std::vector<std::string>>`类型的参数的函数调用上(而并不需要函数的参数非得是`Pixel`或者`Map`)。

## 声明新别名的方式

在现代C++里有两种方式声明类型别名,第一种是传统的`typedef`关键字:

        typedef [原有类型] [你要的别名];

例如:

        typedef int Pixel;
        typedef std::map<std::string, std::vector<std::string>> Map;

而另一种声明别名的方式则是通过使用从C++11开始引入的`using`关键字来实现的:

        using [你要的别名] = [原有类型];

例如:

        using Pixel = int;
        using Map = std::map<std::string, std::vector<std::string>>;

效果上,这两种方式是相同的。最终你都可以使用`Pixel`和`Map`这两个你定义的新名称,想怎么用就怎么用。但……

## `using`最适合模板

上文的`Map`的定义(不管是用`typedef`还是`using`)它本来的类型已经被定死了:永远只会是一个`std::map<std::string, std::vector<std::string>>`,改不了的,比如你想用一个类型为`std::map<int, std::vector<int>>`的`Map`,你就得重新用另一个别名了。

但C++11的`using`其实能够创建“模板别名”:可以给类型模板起别名。它打开了一扇门,使你能指定原有类型里的模板参数。
定义的方式如下:

        template<[模板参数列表]> using [你要的别名] = [原有类型];

例如:

        template<typename T1, typename T2> using Map = std::map<T1, std::vector<T2>>;

然后我就可以定义不同类型的`Map`变量了:

        // 实际类型:std::map<std::string, std::vector<std::string>> (和上文例子里相同)
        Map<std::string, std::string> map1;
       
        // 实际类型:std::map<int, std::vector<int>>
        Map<int, int> map2;
       
        // 实际类型:std::map<int, std::vector<float>>
        Map<int, float> map3;

虽然其实使用传统的`typedef`也可以实现相同的效果,但是非常难设计、复杂棘手。不值得弄。

## 模板声明不能被放在代码块里

你可以把类型别名定义放在任何位置,不管是用`typedef`还是`using`,你都可以放在任意地方:命名空间里、类里,或者块里(`{}`里面)

但模板别名则和别的C++模板一样遵循一个规则:它们不能被放在块里,因为它们最终都是模板定义,所以都是放在命名空间里,或者不使用命名空间的时候放全局位置。

## 参考来源

cprogramming.com - (https://www.cprogramming.com/tutorial/typedef.html)
cppreference.com - (https://en.cppreference.com/w/cpp/language/type_alias)
cppreference.com - (https://en.cppreference.com/w/cpp/language/typedef)
StackOverflow - (https://stackoverflow.com/questions/10747810/what-is-the-difference-between-typedef-and-using-in-c11)

Golden Blonde 发表于 2022-2-15 15:26:35

就是语法糖。

但我认为这不是啥好事情,每个人都选择性用不同的语法做同样的事情,这导致代码的可交流性降低,因为大部分程序员不可能了解所有的语法。

所以吧,我写代码的时候,还是坚持用C99标准。一些老人写C代码的时候,甚至还坚持用C89标准。

0xAA55 发表于 2022-2-18 16:53:22

美俪女神 发表于 2022-2-15 15:26
就是语法糖。

但我认为这不是啥好事情,每个人都选择性用不同的语法做同样的事情,这导致代码的可交流性降 ...

那你敢不敢写C语言的时候不使用一句宏?
页: [1]
查看完整版本: 【翻译】【C++】现代C艹中的using与typedef