C 11中的'typedef'和'using'有什么区别?

新手上路,请多包涵

我知道在 C++11 中我们现在可以使用 using 来编写类型别名,例如 typedef s:

 typedef int MyInt;

据我了解,相当于:

 using MyInt = int;

新语法源于努力表达“模板类型定义”:

 template< class T > using MyType = AnotherType< T, MyAllocatorType >;

但是,对于前两个非模板示例,标准中是否还有其他细微差别?例如, typedef 以“弱”方式进行别名。也就是说,它不会创建新类型,而只会创建一个新名称(这些名称之间的转换是隐含的)。

using 是否相同,还是会生成新类型?有什么不同吗?

原文由 Klaim 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 479
2 个回答

以下所有标准参考均指 N4659:2017 年 3 月 Kona 后工作草案/C++17 DIS


Typedef 声明可以用作初始化语句,而别名声明不能(+)用作初始化语句

但是,对于前两个非模板示例,标准中是否还有其他细微差别?

  • 语义 差异:无。
  • 允许的上下文中的 差异:一些(++) 。

(+) P2360R0 ( Extend init-statement to allow alias-declaration ) 已被 CWG 批准, 从 C++23 开始,typedef 声明和别名声明之间的这种不一致将被删除。

(++) 除了 别名模板 的例子,在原帖中已经提到过。

相同的语义

[dcl.typedef]/2 [摘录, 强调 我的] 管理

[dcl.typedef]/2 typedef-name 也可以通过 alias-declaration 引入。 using 关键字后面的 标识符 成为 typedef-name ,标识符后面的可选 属性说明 序列属于该 typedef-name这样的 typedef-name 具有与由 typedef 说明符引入的语义相同的语义。 […]

别名声明 引入的 typedef-name 与由 typedef 声明引入的 语义相同

允许的上下文中的细微差别

然而,这 并不 意味着这两种变体对于它们可能被使用 的上下文 具有相同的限制。事实上,尽管是一个极端情况, typedef 声明 是一个 init 语句,因此可以在允许初始化语句的上下文中使用

// C++11 (C++03) (init. statement in for loop iteration statements).
for (typedef int Foo; Foo{} != 0;)
//   ^^^^^^^^^^^^^^^ init-statement
{
}

// C++17 (if and switch initialization statements).
if (typedef int Foo; true)
//  ^^^^^^^^^^^^^^^ init-statement
{
    (void)Foo{};
}

switch (typedef int Foo; 0)
//      ^^^^^^^^^^^^^^^ init-statement
{
    case 0: (void)Foo{};
}

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (typedef int Foo; Foo f : v)
//   ^^^^^^^^^^^^^^^ init-statement
{
    (void)f;
}

for (typedef struct { int x; int y;} P; auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}})
//   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ init-statement
{
    (void)x;
    (void)y;
}

别名声明 不是 init-statement ,因此 不能 在允许初始化语句的上下文中使用

// C++ 11.
for (using Foo = int; Foo{} != 0;) {}
//   ^^^^^^^^^^^^^^^ error: expected expression

// C++17 (initialization expressions in switch and if statements).
if (using Foo = int; true) { (void)Foo{}; }
//  ^^^^^^^^^^^^^^^ error: expected expression

switch (using Foo = int; 0) { case 0: (void)Foo{}; }
//      ^^^^^^^^^^^^^^^ error: expected expression

// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for (using Foo = int; Foo f : v) { (void)f; }
//   ^^^^^^^^^^^^^^^ error: expected expression

原文由 dfrib 发布,翻译遵循 CC BY-SA 4.0 许可协议

这两个关键字是等效的,但有一些注意事项。一个是用 using T = int (*)(int, int); 声明函数指针比用 typedef int (*T)(int, int); 更清楚。其次是 typedef 不能使用模板别名形式。第三是公开 C API 需要在公共标头中 typedef

原文由 marski 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题