Kla*_*aim 833 c++ typedef using-declaration c++11
我知道在C++ 11中我们现在可以using用来写类型别名,比如typedefs:
typedef int MyInt;
Run Code Online (Sandbox Code Playgroud)
从我的理解,相当于:
using MyInt = int;
Run Code Online (Sandbox Code Playgroud)
这种新语法来自于努力表达" template typedef":
template< class T > using MyType = AnotherType< T, MyAllocatorType >;
Run Code Online (Sandbox Code Playgroud)
但是,对于前两个非模板示例,标准中是否还有其他细微差别?例如,typedefs以"弱"方式进行别名.也就是说,它不会创建新类型,而只会创建新名称(这些名称之间隐含的转换).
它是否与using生成新类型相同或是否生成新类型?有什么不同吗?
Jes*_*ood 538
它们与标准(强调我的)(7.1.3.2)相同:
也可以通过别名声明引入typedef-name.using关键字后面的标识符变为typedef-name,并且该标识符后面的可选attribute-specifier-seq属于该typedef-name.它具有与typedef说明符引入的语义相同的语义.特别是,它没有定义新类型,它不应出现在type-id中.
小智 202
它们大致相同,除了:
别名声明与模板兼容,而C样式typedef则不兼容.
4xy*_*4xy 192
在模板中使用时,using语法具有优势.如果需要类型抽象,还需要保留模板参数以便将来可以指定.你应该写这样的东西.
template <typename T> struct whatever {};
template <typename T> struct rebind
{
typedef whatever<T> type; // to make it possible to substitue the whatever in future.
};
rebind<int>::type variable;
template <typename U> struct bar { typename rebind<U>::type _var_member; }
Run Code Online (Sandbox Code Playgroud)
但是使用语法简化了这个用例.
template <typename T> using my_type = whatever<T>;
my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }
Run Code Online (Sandbox Code Playgroud)
dfr*_*fri 89
以下所有标准参考均指N4659:2017 年 3 月后 Kona 工作草案/C++17 DIS。
但是,对于前两个非模板示例,标准中是否还有其他细微的差异?
(1)除了别名模板的例子,在原帖中已经提到过。
受[dcl.typedef]/2 [extract,强调我的]管辖
[dcl.typedef] / 2甲 typedef的名称 ,也可以通过引入的 别名声明。的标识符下面的
using关键字成为 typedef的名称和可选属性说明符-SEQ继标识符appertains到的typedef名。这样的 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;) {}
// C++17 (if and switch initialization statements).
if (typedef int Foo; true) { (void)Foo{}; }
// ^^^^^^^^^^^^^^^ init-statement
switch(typedef int Foo; 0) { case 0: (void)Foo{}; }
// ^^^^^^^^^^^^^^^ init-statement
// C++20 (range-based for loop initialization statements).
std::vector<int> v{1, 2, 3};
for(typedef int Foo; Foo f : v) { (void)f; }
// ^^^^^^^^^^^^^^^ init-statement
for(typedef struct { int x; int y;} P;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ init-statement
auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}}) { (void)x; (void)y; }
Run Code Online (Sandbox Code Playgroud)
而一个别名声明是不是一个初始化语句,并且因此可能不会在环境中使用,它允许初始化语句
// 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
Run Code Online (Sandbox Code Playgroud)
Val*_*lus 24
它们基本相同但using提供了alias templates非常有用的功能.我能找到一个很好的例子如下:
namespace std {
template<typename T> using add_const_t = typename add_const<T>::type;
}
Run Code Online (Sandbox Code Playgroud)
所以,我们可以用std::add_const_t<T>而不是typename std::add_const<T>::type
Rob*_*est 14
我知道原始海报有一个很好的答案,但是对于像我这样在这个线程上磕磕绊绊的人来说,提案中有一个重要的说明,我认为它为这里的讨论增加了一些价值,尤其是评论中关于typedef关键字是否为将来会被标记为已弃用,或因冗余/旧而被删除:
有人建议(重新)使用关键字 typedef ... 来引入模板别名:
Run Code Online (Sandbox Code Playgroud)template<class T> typedef std::vector<T, MyAllocator<T> > Vec;这种表示法的优点是使用已知的关键字来引入类型别名。然而,它也显示了几个缺点 [原文如此],其中在别名不指定类型而是模板的上下文中使用已知的关键字为类型名称引入别名的混淆;
Vec是不是一个类型的别名,不应该采取一个typedef名。名称Vec是家族的名称std::vector<•, MyAllocator<•> >——其中项目符号是类型名称的占位符。因此,我们不建议使用“typedef”语法。另一方面,句子Run Code Online (Sandbox Code Playgroud)template<class T> using Vec = std::vector<T, MyAllocator<T> >;可以阅读/解释为:从现在开始,我将
Vec<T>用作std::vector<T, MyAllocator<T> >. 通过这种阅读,别名的新语法似乎合乎逻辑。
对我来说,这意味着继续支持typedefC++ 中的关键字,因为它仍然可以使代码更具可读性和可理解性。
更新using关键字专门针对模板,并且(如已接受的答案中指出的那样)当您使用非模板using并且typedef在机械上相同时,因此基于可读性和意图交流的选择完全取决于程序员.
小智 8
这两个关键字是等效的,但有一些注意事项。一是声明函数指针 withusing T = int (*)(int, int);比 with 更清晰typedef int (*T)(int, int);。其次是模板别名形式不能与typedef. 第三是公开 C API 需要typedef在公共头文件中。
| 归档时间: |
|
| 查看次数: |
248428 次 |
| 最近记录: |