Jaka jest różnica między 'typedef' a 'using' w C++11?
Wiem, że w C++11 możemy teraz używać using
do pisania aliasów typu, np. typedef
s:
typedef int MyInt;
Jest, z tego co rozumiem, odpowiednikiem:
using MyInt = int;
I ta nowa składnia powstała z wysiłku, aby mieć sposób na wyrażenie "szablon typedef":
template< class T > using MyType = AnotherType< T, MyAllocatorType >;
Ale czy przy pierwszych dwóch przykładach nie szablonowych są jakieś inne subtelne różnice w standardzie? Na przykład, typedef
robią aliasing w "słaby" sposób. Oznacza to, że nie tworzy nowego typu, ale tylko nową nazwę (konwersje są niejawne między tymi nazwami).
Jest to to samo z using
czy generuje nowy typ? Czy są jakieś różnice?
7 answers
wszystkie standardowe odniesienia poniżej odnoszą się do N4659: Marzec 2017 Post-Kona working draft/C++17 dis.
Deklaracje Typedef mogą, podczas gdy deklaracje aliasów nie mogą być używane jako instrukcje inicjalizacji
Ale, z dwoma pierwszymi przykładami nie szablonowymi, są są jakieś inne subtelne różnice w standardzie?
- różnice w semantyce : brak.
- różnice w dozwolonych kontekstach : niektóre(1).
(1) oprócz przykładów szablonów aliasów , o których już wspomniano w oryginalnym poście.
Ta sama semantyka
Zgodnie z [dcl.typedef]/2 [Wyciąg, podkreślenie moje]
[dcl.typedef] / 2 A typedef-name może być również wprowadzony przez alias-deklaracja. Identyfikator po
using
słowo kluczowe staje się typedef-name i opcjonalny atrybut-specifier-seq po identyfikatorze przypisany do typedef-name. taki typedef-name ma taką samą semantykę, jakby została wprowadzona przez specyfikatortypedef
. [...]
A typedef-name wprowadzony przez alias-declaration ma tę samą semantykę tak, jakby został wprowadzony przez typedef
deklaracja.
Subtelne różnica w dozwolonych kontekstach
Nie oznacza to jednak , że te dwie odmiany mają takie same ograniczenia w odniesieniu do kontekstów , w których mogą być używane. I rzeczywiście, choć sprawa narożna, a deklaracja typedef jest INIT-oświadczenie i mogą być używane w kontekstach, które pozwalają na inicjalizację instrukcji
// 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; }
alias-deklaracja jest Nie an INIT-statement, a zatem nie może być używane w kontekstach, które pozwalają na inicjalizację instrukcji
// 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-07 17:59:25
Są równoważne ze standardem (7.1.3.2):
Typedef-name może być również wprowadzony przez alias-declaration. Na identifier following the using keyword becomes a typedef-name and the opcjonalny atrybut-specifier-seq po pojawieniu się identyfikatora do tego imienia. ma tę samą semantykę, jakby była wprowadzony przez typedef specifier. w szczególności nie definiuje nowego typu i nie pojawia się w type-id.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-25 03:16:42
Są w dużej mierze takie same, z tym że:
Deklaracja aliasu jest zgodna z szablonami, natomiast C styl typedef nie jest.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 14:54:25
Składnia z użyciem składni ma przewagę, gdy jest używana w szablonach. Jeśli potrzebujesz abstrakcji typu, ale także musisz zachować parametr szablonu, aby mógł być określony w przyszłości. Powinieneś napisać coś takiego.
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; }
Ale użycie składni upraszcza ten przypadek użycia.
template <typename T> using my_type = whatever<T>;
my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-24 12:51:25
Są zasadniczo takie same, ale using
Dostarcza alias templates
, co jest całkiem przydatne. Jeden dobry przykład, który mogłem znaleźć jest następujący:
namespace std {
template<typename T> using add_const_t = typename add_const<T>::type;
}
Więc możemy użyć std::add_const_t<T>
zamiast typename std::add_const<T>::type
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-31 08:20:30
Wiem, że oryginalny plakat ma świetną odpowiedź, ale dla każdego, kto natknie się na ten wątek, jak mam, jest ważna uwaga z propozycja , która moim zdaniem dodaje coś wartościowego do dyskusji tutaj, szczególnie do obaw w komentarzach o tym, czy słowo kluczowe typedef
zostanie oznaczone jako przestarzałe w przyszłości lub usunięte za bycie zbędnym/starym:{[15]]}
Zasugerowano (ponowne) użycie słowa kluczowego typedef ... aby wprowadzić szablon aliasy:
template<class T> typedef std::vector<T, MyAllocator<T> > Vec;
Ta notacja ma tę zaletę, że używa się już znanego słowa kluczowego do wprowadzenia aliasu typu. Jednak wyświetla również kilka dezawantacji [sic], wśród których mylenie użycia słowa kluczowego znanego z wprowadzenia aliasu dla nazwy typu w kontekście, w którym alias nie oznacza typu, ale szablon;
Vec
jest , a nie aliasem dla typu i nie powinien być brany za typedef-name. Nazwa {[3] } jest nazwą rodzinystd::vector<•, MyAllocator<•> >
- gdzie kula jest symbol zastępczy dla nazwy typu.W związku z tym nie proponujemy składni "typedef".Z drugiej strony zdanietemplate<class T> using Vec = std::vector<T, MyAllocator<T> >;
Można odczytać/zinterpretować jako: od teraz będę używać
Vec<T>
jako synonimu dlastd::vector<T, MyAllocator<T> >
. Przy takim odczycie Nowa składnia aliasingu wydaje się w miarę logiczna.
Dla mnie oznacza to ciągłe wsparcie dla typedef
słowa kluczowego w C++, ponieważ może to jeszcze uczynić kod bardziej czytelnym i zrozumiałym.
Aktualizacja using
słowo kluczowe było przeznaczone specjalnie dla szablonów i (jak zaznaczono w zaakceptowanej odpowiedzi), gdy pracujesz z nie-szablonami using
i {[2] } są mechanicznie identyczne, więc wybór należy całkowicie do programisty ze względu na czytelność i komunikowanie intencji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-12 02:59:59
Oba słowa kluczowe są równoważne, ale jest kilka zastrzeżeń. Jednym z nich jest to, że deklarowanie wskaźnika funkcji za pomocą using T = int (*)(int, int);
jest jaśniejsze niż za pomocą typedef int (*T)(int, int);
. Po drugie, forma aliasu szablonu nie jest możliwa z typedef
. Po trzecie, ujawnienie C API wymagałoby typedef
w nagłówkach publicznych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-02 22:23:42