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


905

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

typedef int MyInt;

据我了解,相当于:

using MyInt = int;

并且这种新语法是通过努力表达“ template typedef” 的方式而出现的:

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

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

与它相同using还是会生成新类型?有什么区别吗?


215
我个人更喜欢新语法,因为它与常规变量赋值非常相似,从而提高了可读性。例如,您喜欢typedef void (&MyFunc)(int,int);还是using MyFunc = void(int,int);
Matthieu M.

13
我完全同意,我现在只使用新语法。这就是为什么我要问,确保没有任何区别。
克莱姆

80
@MatthieuM。这两个人是不同的。应该是typedef void MyFunc(int,int);(实际上看起来还不错),或者using MyFunc = void(&)(int,int);
R. Martinho Fernandes

5
@ R.MartinhoFernandes为什么你需要()using MyFunc = void(&)(int,int);?它是指MyFunc对功能的引用吗?如果您省略怎么办?
Rich

7
是的,它是一个函数参考。等同于typedef void (&MyFunc)(int,int);。如果您忽略&它,则相当于typedef void MyFunc(int,int);
R. Martinho Fernandes

Answers:


584

它们与标准(强调我的)(7.1.3.2)是等效的:

typedef名称也可以通过别名声明来引入。using关键字后面的标识符变为typedef名称,而标识符后面的可选attribute-specifier-seq属于该typedef名称。它具有与typedef说明符引入的语义相同的语义。特别是,它没有定义新的类型,也不应出现在type-id中。


24
从答案来看,using关键字似乎是的超集typedef。那么,将来typdef会不推荐使用吗?
iammilind

49
弃用并不一定表示要删除它-它只是强烈建议使用其他方式。
Iron Savior

18
但是我不知道为什么他们不只允许将typedef模板化。我记得在某处读过他们介绍using语法的原因恰恰是因为typedef语义在模板中不能很好地工作。这在某种程度上与using定义为具有完全相同的语义的事实相矛盾。
celtschk

12
@celtschk:提案中讨论了原因n1489。模板别名不是类型的别名,而是一组模板的别名。区分两者之间typedef需要新的语法。另外,请记住,OP的问题是有关非模板版本之间的区别。
杰西·古德

4
那么为什么要引入这种冗余呢?2种语法用于相同目的。而且我看不到typdef被弃用。
伯努瓦

237

它们基本相同,除了:

别名声明与模板兼容,而C风格的typedef不兼容。


29
特别喜欢答案的简单性并指出排版的由来。
g24l 2015年

1
@ g24l您的意思是typedef ... 可能
Marc.2377'9

typedef我可能会问,C和C ++有什么区别?
McSinyx

196

在模板中使用时,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; }

但是使用语法可以简化此用例。

template <typename T> using my_type = whatever<T>;

my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }

35
我已经在问题中指出了这一点。我的问题是关于您是否不使用模板,是否与typedef有区别。例如,当您使用“ Foo foo {init_value};”时 而不是'Foo foo(init_value)'都应该做同样的事情,但是不要完全遵循相同的规则。所以我想知道使用/ typedef是否存在类似的隐藏差异。
克莱姆2014年

24

它们本质上是相同的,但是using提供了alias templates非常有用的功能。我可以找到一个很好的例子,如下所示:

namespace std {
 template<typename T> using add_const_t = typename add_const<T>::type;
}

因此,我们可以使用std::add_const_t<T>代替typename std::add_const<T>::type


据我所知,在std名称空间内添加任何内容都是不确定的行为
someonewithpc

5
@someonewithpc我没有添加任何东西,它已经存在,我只是显示一个使用类型名的示例。请检查en.cppreference.com/w/cpp/types/add_cv
Validus Oculus,

9

我知道原始张贴者有一个很好的答案,但是对于像我这样绊脚石的任何人,提案中都有一个重要说明,我认为这为此处的讨论增添了一些价值,尤其是对于typedef关键字是否为将来将被标记为已弃用,或由于冗余/旧而被删除:

已建议(重新)使用关键字typedef ...引入模板别名:

template<class T>
  typedef std::vector<T, MyAllocator<T> > Vec;

该符号的优点是使用已知的关键字来引入类型别名。但是,它也显示了一些不足之处,其中,在别名不是指定类型而是模板的情况下,使用已知为类型名称引入别名的关键字会造成混淆。Vec不是一个类型的别名,不应该采取一个typedef名。名称Vec是家庭的名称,std::vector<•, MyAllocator<•> >其中项目符号是类型名称的占位符。因此,我们不建议使用“ typedef”语法。

template<class T>
  using Vec = std::vector<T, MyAllocator<T> >;

可以理解为:从现在开始,我将Vec<T>用作的同义词std::vector<T, MyAllocator<T> >。通过阅读,别名的新语法似乎是合理的。

对我来说,这意味着将继续支持typedefC ++中的关键字,因为它仍然可以使代码更易于理解

更新using关键字专门针对模板,并且(如在接受的答案中指出的那样)当您使用非模板using并且typedef在机械上相同时,因此选择完全取决于程序员的可读性和意图传达。


2

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.