What are the differences between using
from typedef
besides the fact that using
works with templates? If only in this, then why it was impossible to add this support in typedef
?
4 answers
The using
directive exists only in С++
, typedef
is a legacy from pure C
, there are no templates in it.
Especially since they differ in nature. When using typedef
we create a synonym for a type name, and using
allows you to create a type synonym, or include an existing name in the current namespace.
- those. Is it at the level of a fatal flaw? I always thought that typedef created a new typeid, but now I entered the following: ideone.com/KAW340 - arukasa
- updated the answer,
typedef
sets a synonym for the name - Yuriy Orlov - oneNamespaces are generally out of place here, because
using
as atypedef
replacement is not the case thatusing
is a declaration or a directive. - αλεχολυτ
using
allows you to write more beautiful code and allows you to get rid of the typedef
legacy, which has def
in its name, which may imply a definition
that does not actually occur. using
is a typedef
replacement with some additions which typedef
does not have. There is no point in using typedef
in modern code.
In more detail about what those who suggested this change in the standard think about, as well as using
history, you can read on the English part of SO .
I would say this - the main advantage of using
over typedef
is when working with templates. patterns. In particular, alias declarations can be template-based (and in this case they are called alias templates), while typedef
are not. This gives C ++ 11 programmers a simple mechanism for expressing what in C ++ 98 could be expressed only by hacker methods, using typedef
nested in a template struct
. Consider, for example, the definition of a synonym for a linked list that uses a custom memory MyAlloc
. In the case of alias templates, this is simple:
// MyAllocList<T> является синонимом для std::list<T,MyAlloc<T>>: template<typename T> using MyAllocList = std::list<T, MyAlloc<T>>; MyAllocList<Widget> lw; // Клиентский код
In the case of typedef you have to go a long circular path:
// MyAllocList<T>::type — синоним для std::list<T,MyAlloc<T>>: template<typename T> struct MyAllocList { typedef std::list<T, MyAlloc<T>> type; }; MyAllocList<Widget>::type lw; // Клиентский код
All the worse. If you want to use a typedef
in a template to create a linked list that stores objects of the type specified by the template parameter, the name specified in typedef
should be preceded by the typename
keyword:
template<typename T> class Widget { // Widget<T> содержит private: // MyAllocList<T>, typename MyAllocList<T>::type list; // как член-данные … };
Here MyAllocList<T>::type
refers to a type that depends on the template type parameter ( T
). Thus, MyAllocList<T>::type
is a dependent type, and one of the C ++ rules requires that the names of dependent types are preceded by the keyword typename
.
If MyAllocList
defined as an alias pattern, this requirement of using the typename
keyword is removed (as is the cumbersome “ ::type
” suffix):
template<typename T> using MyAllocList = std::list<T, MyAlloc<T>>; // Как и ранее template<typename T> class Widget { private: MyAllocList<T> list; // Ни typename, … // ни ::type };
For you, MyAllocList<T>
(i.e. using an alias pattern) may look like it is dependent on a template parameter T
, like MyAllocList<T>::type
(i.e., like using a nested typedef
), but you are not a compiler. When the compiler processes the Widget
template and encounters using MyAllocList<T>
(i.e. using an alias pattern), it knows that MyAllocList<T>
is a type name, because MyAllocList
is an alias pattern: it must be a type name. Thus, MyAllocList<T>
is an independent type, and the typename
specifier is neither required nor allowed.
On the other hand, when the compiler sees MyAllocList<T>::type
(that is, using nested typedef
) in the Widget
template, it cannot know for sure that this construct names a type, since it can be the MyAllocList
specialization with which it still not encountered and in which MyAllocList<T>::type
refers to something other than type. It sounds silly, but don't blame the compilers for considering this possibility. In the end, it's people who write such code. For example, a certain lost soul is quite able to write the following:
class Wine { … }; template<> // Специализация MyAllocList в class MyAllocList<Wine> { // которой T представляет собой Wine private: enum class WineType // См. в разделе 3.4 информацию об { White, Red, Rose }; // "enum class" WineType type; // В этом классе type представляет … // собой данные-член! };
As you can see, MyAllocList<Wine>::type
not a type. If the Widget
instantiated with Wine
, the MyAllocList<T>::type
in the Widget
template is a member data, not a type. Whether MyAllocList<T>::type
refers to a type in a Widget
template depends on what T
, and therefore compilers require you to specify that it is a type preceding it with the keyword typename
.
Another convenience of using
compared to typedef
can be seen in the example of a pointer to a function (argument int, returns float):
typedef float (*func_ptr)(int); using func_ptr = float (*)(int);
This is a matter of taste, but I prefer the second option.
Subtracted from Scott Myers