C ++ 11中的'typedef'和'using'有什么区别?
我知道在 C++11 中我们现在可以使用 using
来编写类型别名,例如 typedef
s:
I know that in C++11 we can now use using
to write type alias, like typedef
s:
typedef int MyInt;
据我了解,相当于:
using MyInt = int;
新语法源于努力表达模板类型定义":
And that new syntax emerged from the effort to have a way to express "template typedef":
template< class T > using MyType = AnotherType< T, MyAllocatorType >;
但是,对于前两个非模板示例,标准中是否还有其他细微差别?例如,typedef
在弱"类中做别名.大大地.也就是说,它不会创建新类型,而只会创建新名称(这些名称之间隐含转换).
But, with the first two non-template examples, are there any other subtle differences in the standard? For example, typedef
s do aliasing in a "weak" way. That is it does not create a new type but only a new name (conversions are implicit between those names).
和 using
是一样的还是生成一个新的类型?有什么不同吗?
Is it the same with using
or does it generate a new type? Are there any differences?
推荐答案
以下所有标准参考参考N4659:2017 年 3 月后 Kona 工作草案/C++17 DIS.
但是,对于前两个非模板示例,标准还有其他细微差别吗?
But, with the first two non-template examples, are there any other subtle differences in the standard?
- 语义差异:无.
- 允许的上下文中的差异:一些(1).
- Differences in semantics: none.
- Differences in allowed contexts: some(1).
(1)除了原帖中已经提到的别名模板的例子.
由 [dcl.typedef]/2 [提取,强调我的]
[dcl.typedef]/2 Atypedef-name一个>也可以由一个引入别名声明一个>.using
关键字后面的 identifier 成为typedef-name 和 identifier 后面的可选 attribute-specifier-seq 属于该 typedef-name.这样的typedef-name 具有与 typedef
说明符引入的语义相同的语义. [...]
[dcl.typedef]/2 A typedef-name can also be introduced by an alias-declaration. The identifier following the
using
keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. Such a typedef-name has the same semantics as if it were introduced by thetypedef
specifier. [...]
别名声明引入的typedef-name与typedef<引入的语义相同/code> 声明.
a typedef-name introduced by an alias-declaration has the same semantics as if it were introduced by the typedef
declaration.
但是,这并不不暗示这两种变体在可能使用它们的上下文方面具有相同的限制.事实上,尽管是一个极端情况,typedef 声明 是一个 init-statement 因此可以在允许初始化语句的上下文中使用
However, this does not imply that the two variations have the same restrictions with regard to the contexts in which they may be used. And indeed, albeit a corner case, a typedef declaration is an init-statement and may thus be used in contexts which allow initialization statements
// 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;
}
而 别名声明 不是 初始化语句,因此不能在允许初始化语句的上下文中使用
whereas an alias-declaration is not an init-statement, and thus may not be used in contexts which allows initialization statements
// 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
相关文章