以下所有标准参考均指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