以下所有标准参考均指N4659: 2017年3月Kona后工作草案/C++17 DIS。
typedef声明可以作为初始化语句,而别名声明不行(+)
但是,在前两个非模板示例中,标准中是否还有其他细微差别呢?
- 语义上的差异:没有。
- 允许的上下文差异:一些(++)。
(+) P2360R0(扩展init-statement以允许alias-declaration)已被CWG批准,截至C++23,typedef声明和别名声明之间的这种不一致性将被消除。
(++) 除了已在原帖中提到的别名模板示例之外。
相同的语义
根据[dcl.typedef]/2 [摘录,重点是我的]
[dcl.typedef]/2 也可以通过alias-declaration引入一个typedef-name。紧随using
关键字后面的标识符成为一个typedef-name,后面的可选attribute-specifier-seq与该typedef-name有关。 通过typedef
限定符引入的typedef-name具有与通过alias-declaration引入的typedef-name相同的语义。 [...]
通过alias-declaration引入的typedef-name具有与通过typedef
声明引入的typedef-name相同的语义。
允许上下文中的微妙差异
然而,这并不意味着这两个变量在使用
上下文的限制方面相同。实际上,虽然只是一个角落的情况,
typedef声明是一个
init语句,因此可以在允许初始化语句的上下文中使用。
for (typedef int Foo; Foo{} != 0;)
{
}
if (typedef int Foo; true)
{
(void)Foo{};
}
switch (typedef int Foo; 0)
{
case 0: (void)Foo{};
}
std::vector<int> v{1, 2, 3};
for (typedef int Foo; Foo f : v)
{
(void)f;
}
for (typedef struct { int x; int y;} P; auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}})
{
(void)x;
(void)y;
}
与别名声明不同的是,它不是初始化语句,因此不能在允许初始化语句的上下文中使用
for (using Foo = int; Foo{} != 0;) {}
if (using Foo = int; true) { (void)Foo{}; }
switch (using Foo = int; 0) { case 0: (void)Foo{}; }
std::vector<int> v{1, 2, 3};
for (using Foo = int; Foo f : v) { (void)f; }
typedef void (&MyFunc)(int,int);
还是using MyFunc = void(int,int);
? - Matthieu M.typedef void MyFunc(int,int);
(看起来其实还不错), 或者using MyFunc = void(&)(int,int);
。 - R. Martinho Fernandesusing MyFunc = void(&)(int,int);
中,为什么需要 (&) ?这是不是意味着MyFunc
是一个指向函数的引用?如果省略 & 会怎样? - Richtypedef void (&MyFunc)(int,int);
。如果省略&
,则相当于typedef void MyFunc(int,int);
。 - R. Martinho Fernandes