W C ++ 11 using
słowo kluczowe użyte do type alias
jest identyczne z typedef
.
7.1.3.2
Nazwę typedef można również wprowadzić za pomocą deklaracji aliasu. Identyfikator następujący po słowie kluczowym using staje się nazwą typu typedef, a opcjonalna sekwencja specyfikatora atrybutu następująca po identyfikatorze odnosi się do tej nazwy typu. Ma taką samą semantykę, jak gdyby została wprowadzona przez specyfikator typedef. W szczególności nie definiuje nowego typu i nie pojawia się w identyfikatorze typu.
Bjarne Stroustrup podaje praktyczny przykład:
typedef void (*PFD)(double); // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP
Pre-C ++ 11, using
słowo kluczowe może przenosić funkcje składowe w zakres. W C ++ 11 możesz teraz zrobić to dla konstruktorów (kolejny przykład Bjarne Stroustrupa):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
Ben Voight podaje całkiem dobry powód dla uzasadnienia niewprowadzania nowego słowa kluczowego lub nowej składni. Standard chce jak najbardziej uniknąć łamania starego kodu. Dlatego w dokumentach wniosku będzie można zobaczyć odcinki podoba Impact on the Standard
, Design decisions
i jak mogą one wpłynąć starszego kodu. Są sytuacje, w których propozycja wydaje się być naprawdę dobrym pomysłem, ale może nie mieć znaczenia, ponieważ byłaby zbyt trudna do wdrożenia, zbyt zagmatwana lub byłaby sprzeczna ze starym kodem.
Oto stara praca z 2003 n1449 . Wydaje się, że uzasadnienie dotyczy szablonów. Ostrzeżenie: mogą wystąpić literówki z powodu kopiowania z pliku PDF.
Najpierw rozważmy przykład zabawki:
template <typename T>
class MyAlloc {/*...*/};
template <typename T, class A>
class MyVector {/*...*/};
template <typename T>
struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage
Podstawowym problemem związanym z tym idiomem i głównym faktem motywującym dla tej propozycji jest to, że idiom powoduje, że parametry szablonu pojawiają się w kontekście niemożliwym do wyprowadzenia. Oznacza to, że nie będzie możliwe wywołanie poniższej funkcji foo bez jawnego określenia argumentów szablonu.
template <typename T> void foo (Vec<T>::type&);
Tak więc składnia jest nieco brzydka. Wolelibyśmy uniknąć zagnieżdżenia ::type
Wolelibyśmy coś takiego:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Zwróć uwagę, że w szczególności unikamy terminu „typedef template” i wprowadzamy nową składnię obejmującą parę „using” i „=”, aby uniknąć nieporozumień: nie definiujemy tutaj żadnych typów, wprowadzamy synonim (tj. Alias) dla abstrakcja identyfikatora typu (tj. wyrażenie typu) obejmująca parametry szablonu. Jeśli parametry szablonu są używane w kontekstach możliwych do wyprowadzenia w wyrażeniu typu, to za każdym razem, gdy alias szablonu jest używany do utworzenia identyfikatora szablonu, można wydedukować wartości odpowiednich parametrów szablonu - więcej na ten temat będzie dalej. W każdym razie możliwe jest teraz pisanie funkcji ogólnych, które działają Vec<T>
w kontekście dającym się wyprowadzić, a także poprawiona została składnia. Na przykład moglibyśmy przepisać foo jako:
template <typename T> void foo (Vec<T>&);
Podkreślamy tutaj, że jednym z głównych powodów proponowania aliasów szablonów było to, aby dedukcja argumentów i wywołanie foo(p)
zakończyły się sukcesem.
Kolejny dokument n1489 wyjaśnia, dlaczego using
zamiast używać typedef
:
Zaproponowano (ponownie) użycie słowa kluczowego typedef - tak jak to zrobiono w artykule [4] - w celu wprowadzenia aliasów szablonów:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Ta notacja ma tę zaletę, że używa już znanego słowa kluczowego do wprowadzenia aliasu typu. Jednak wyświetla również kilka wad, między innymi zamieszanie związane ze stosowaniem słowa kluczowego, o którym wiadomo, że wprowadza alias dla nazwy typu w kontekście, w którym alias nie oznacza typu, ale szablon; Vec
nie jest aliasem dla typu i nie powinien być traktowany jako nazwa typu typedef. Nazwa Vec
to nazwa rodziny std::vector< [bullet] , MyAllocator< [bullet] > >
- gdzie punktor jest symbolem zastępczym nazwy typu. W związku z tym nie proponujemy składni „typedef”. Z drugiej strony zdanie
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
można odczytać / zinterpretować jako: od teraz będę używać Vec<T>
jako synonimu dla std::vector<T, MyAllocator<T> >
. Po tym odczytaniu nowa składnia aliasingu wydaje się całkiem logiczna.
Myślę, że istnieje tutaj ważne rozróżnienie, alias es zamiast typu s. Inny cytat z tego samego dokumentu:
Deklaracja aliasu jest deklaracją, a nie definicją. Deklaracja aliasu wprowadza nazwę do deklaratywnego regionu jako alias dla typu wyznaczonego przez prawą stronę deklaracji. Sedno tej propozycji dotyczy aliasów nazw typów, ale notację można oczywiście uogólnić, aby zapewnić alternatywną pisownię aliasów przestrzeni nazw lub zestawu nazewnictwa przeciążonych funkcji (dalsze omówienie znajduje się w ✁ 2.3). [ Moja uwaga: ta sekcja omawia, jak może wyglądać ta składnia i powody, dla których nie jest częścią propozycji. ] Można zauważyć, że deklaracja aliasu produkcji gramatyki jest akceptowalna wszędzie tam, gdzie dopuszczalna jest deklaracja typedef lub definicja aliasu przestrzeni nazw.
Podsumowanie, do roli using
:
- aliasy szablonów (lub definicje typów szablonów, pierwszy jest preferowany w odniesieniu do nazwy)
- aliasy przestrzeni nazw (tj.
namespace PO = boost::program_options
iusing PO = ...
równoważne)
- dokument mówi
A typedef declaration can be viewed as a special case of non-template alias-declaration
. To zmiana estetyczna iw tym przypadku jest uważana za identyczną.
- wnoszenie czegoś do zakresu (na przykład
namespace std
do zasięgu globalnego), funkcje składowe, dziedziczenie konstruktorów
Nie można go używać do:
int i;
using r = i; // compile-error
Zamiast tego zrób:
using r = decltype(i);
Nazywanie zestawu przeciążeń.
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);