Automatyczne słowo kluczowe C ++. Dlaczego to magia?

145

Z całego materiału, którego używałem do nauki C ++, autozawsze był dziwny specyfikator czasu przechowywania, który nie służył żadnemu celowi. Ale niedawno napotkałem kod, który używał go jako nazwy typu. Spróbowałem z ciekawości i przyjmuje on rodzaj tego, co mu przydzielę!

Nagle iteratory STL i, cóż, wszystko, co używa szablonów, jest 10-krotnie łatwiejsze do napisania. Mam wrażenie, że używam „zabawnego” języka, takiego jak Python.

Gdzie to słowo kluczowe było przez całe moje życie? Czy możesz przerwać moje marzenia, mówiąc, że jest dostępny wyłącznie dla studia wizualnego, czy nie jest przenośny?

Anne Quinn
źródło
18
to nie jest. magia. Jest nowy ( o nie, co za zła gra słów ). Teraz asynchroniczny jest przyszłość ( westchnienie )
sehe
2
Oto odniesienie na temat automatycznych słów kluczowych en.cppreference.com/w/cpp/language/auto
andyqee

Odpowiedzi:

149

auto było słowem kluczowym, które C ++ „odziedziczyło” po C, które istniało prawie od zawsze, ale praktycznie nigdy nie było używane, ponieważ były tylko dwa możliwe warunki: albo było niedozwolone, albo było zakładane domyślnie.

Użycie autodo oznaczania wydedukowanego typu było nowe w C ++ 11.

Jednocześnie auto x = initializerdedukuje typ xz typu w initializertaki sam sposób, jak działa dedukcja typu szablonu dla szablonów funkcji. Rozważmy taki szablon funkcji:

template<class T>
int whatever(T t) { 
    // point A
};

W punkcie A przypisano typ na Tpodstawie wartości przekazanej dla parametru do whatever. Kiedy to zrobisz auto x = initializer;, ta sama dedukcja typu jest używana do określenia typu na xpodstawie typu initializerużytego do jego zainicjowania.

Oznacza to, że większość mechanizmów dedukcji typów, które kompilator musi zaimplementować, autobyła już obecna i używana w szablonach na każdym kompilatorze, który nawet próbował zaimplementować C ++ 98/03. W związku z tym dodanie obsługi programu autobyło pozornie dość łatwe dla zasadniczo wszystkich zespołów kompilatorów - zostało dodane dość szybko i wydaje się, że było też kilka błędów z nim związanych.

Kiedy ta odpowiedź została pierwotnie napisana (w 2011 roku, zanim tusz wysechł w standardzie C ++ 11) autobył już dość przenośny. Obecnie jest całkowicie przenośny wśród wszystkich głównych kompilatorów. Jedynymi oczywistymi powodami, aby tego uniknąć, byłoby napisanie kodu zgodnego z kompilatorem C lub konkretna potrzeba kierowania na jakiś niszowy kompilator, o którym wiesz, że go nie obsługuje (np. Kilka osób nadal pisze kod dla MS-DOS przy użyciu kompilatorów firm Borland, Watcom itp., które nie widziały znaczących ulepszeń od dziesięcioleci). Jeśli używasz w miarę aktualnej wersji któregokolwiek z głównych kompilatorów, nie ma powodu, aby w ogóle tego unikać.

Jerry Coffin
źródło
24

Po prostu bierze ogólnie bezużyteczne słowo kluczowe i nadaje mu nową, lepszą funkcjonalność. Jest standardem w C ++ 11 i większość kompilatorów C ++ nawet z pewną obsługą C ++ 11 będzie go obsługiwać.

Nicol Bolas
źródło
O! Aha, nigdy nie myślałem, że język C ++ jest czymś, co może się zmienić samo w sobie. Będę musiał sprawdzić, co jeszcze dodali w tym C ++ 11, słyszałem trochę o C ++ 0x, ale nigdy nie zagłębiałem się w to zbyt głęboko.
Anne Quinn
7
@Clairvoire C ++ 0x była nazwą tymczasową. Został opublikowany w tym miesiącu i tym samym stał się C ++ 11.
R. Martinho Fernandes
13

W przypadku zmiennych określa, że ​​typ deklarowanej zmiennej zostanie automatycznie wydedukowany z jej inicjatora. W przypadku funkcji określa, że ​​typ zwracany jest końcowym typem zwracanym lub zostanie wydedukowany z jego instrukcji powrotu (od C ++ 14).

Składnia

auto variable initializer   (1) (since C++11)

auto function -> return type    (2) (since C++11)

auto function   (3) (since C++14)

decltype(auto) variable initializer (4) (since C++14)

decltype(auto) function (5) (since C++14)

auto :: (6) (concepts TS)

cv(optional) auto ref(optional) parameter   (7) (since C++14)

Wyjaśnienie

1) Podczas deklarowania zmiennych w zakresie blokowym, w zakresie przestrzeni nazw, w instrukcjach inicjalizacji pętli for itp. Jako specyfikatora typu można użyć słowa kluczowego auto. Po określeniu typu inicjatora kompilator określa typ, który zastąpi słowo kluczowe auto, korzystając z reguł dedukcji argumentów szablonu z wywołania funkcji (szczegółowe informacje można znaleźć w temacie dedukcja argumentów szablonu # Inne konteksty). Słowa kluczowego auto mogą towarzyszyć modyfikatory, takie jak const lub &, które będą uczestniczyć w dedukcji typu. Na przykład, biorąc pod uwagę const auto& i = expr;, typ i jest dokładnie typem argumentu u w wyimaginowanym szablonie, template<class U> void f(const U& u)jeśli wywołanie funkcjif(expr)został skompilowany. W związku z tym auto && można wywnioskować jako odniesienie l-wartości lub odniesienie r-wartości zgodnie z inicjatorem, który jest używany w pętli for na podstawie zakresu. Jeśli do zadeklarowania wielu zmiennych używane jest auto, wywnioskowane typy muszą być zgodne. Na przykład deklaracja auto i = 0, d = 0.0;jest źle sformułowana, podczas gdy deklaracja auto i = 0, *p = &i;jest poprawnie sformułowana, a auto jest wywnioskowane jako int.

2) W deklaracji funkcji, która używa końcowej składni zwracanego typu, słowo kluczowe auto nie wykonuje automatycznego wykrywania typu. Służy tylko jako część składni.

3) W deklaracji funkcji, która nie używa końcowej składni zwracanego typu, słowo kluczowe auto wskazuje, że typ zwracany zostanie wydedukowany z argumentu operacji instrukcji return przy użyciu reguł dedukcji argumentów szablonu.

4) Jeśli zadeklarowanym typem zmiennej jest decltype (auto), słowo kluczowe auto jest zastępowane wyrażeniem (lub listą wyrażeń) jego inicjatora, a rzeczywisty typ jest wywnioskowany przy użyciu reguł dla decltype.

5) Jeśli zwracany typ funkcji jest zadeklarowany jako decltype (auto), słowo kluczowe auto jest zastępowane operandem instrukcji return, a rzeczywisty typ zwracania jest wywnioskowany przy użyciu reguł dla decltype.

6) Zagnieżdżony specyfikator nazwy w postaci auto :: jest symbolem zastępczym, który jest zastępowany klasą lub typem wyliczenia zgodnie z regułami odliczania symboli zastępczych typu ograniczonego.

7) Deklaracja parametru w wyrażeniu lambda. (od C ++ 14) Deklaracja parametru funkcji. (koncepcje TS)

Uwagi Do C ++ 11, auto miało semantykę specyfikatora czasu przechowywania. Mieszanie zmiennych automatycznych i funkcji w jednej deklaracji, jak w, auto f() -> int, i = 0;jest niedozwolone.

Więcej informacji: http://en.cppreference.com/w/cpp/language/auto

Prathamesh Aware
źródło
11

Tej funkcjonalności nie było przez całe Twoje życie. Jest obsługiwany w programie Visual Studio od wersji 2010. Jest to nowa funkcja C ++ 11, więc nie jest wyłączna dla programu Visual Studio i jest / będzie przenośna. Większość kompilatorów już to obsługuje.

R. Martinho Fernandes
źródło
3

Nigdzie nie idzie ... to nowa standardowa funkcja C ++ w implementacji C ++ 11. Biorąc to pod uwagę, chociaż jest to wspaniałe narzędzie do upraszczania deklaracji obiektów, a także do czyszczenia składni niektórych paradygmatów wywołań (tj. Pętli for opartych na zakresie), nie nadużywaj / nadużywaj tego :-)

Jason
źródło
3

Słowo kluczowe auto określa, że ​​typ deklarowanej zmiennej zostanie automatycznie odjęty od jej inicjatora. W przypadku funkcji, jeśli ich typem zwracanym jest auto, to zostanie to ocenione przez wyrażenie typu zwracanego w czasie wykonywania.

Może to być bardzo przydatne, gdy musimy użyć iteratora. Na przykład dla poniższego kodu możemy po prostu użyć "auto" zamiast pisać całą składnię iteratora.

int main() 
{ 

// Initialize set 
set<int> s; 

s.insert(1); 
s.insert(4); 
s.insert(2); 
s.insert(5); 
s.insert(3); 

// iterator pointing to 
// position where 2 is 
auto pos = s.find(3); 

// prints the set elements 
cout << "The set elements after 3 are: "; 
for (auto it = pos; it != s.end(); it++) 
    cout << *it << " "; 

return 0; 
}

W ten sposób możemy użyć słowa kluczowego „auto”

rahul goyal
źródło
0

To magia to możliwość ograniczenia konieczności pisania kodu dla każdego typu zmiennej przekazywanej do określonych funkcji. Rozważmy podobną do Pythona funkcję print () w jej bazie C.

#include <iostream>
#include <string>
#include <array>

using namespace std;

void print(auto arg) {
     cout<<arg<<" ";
}

int main()
{
  string f = "String";//tok assigned
  int x = 998;
  double a = 4.785;
  string b = "C++ Auto !";
//In an opt-code ASCII token stream would be iterated from tok's as:
  print(a);
  print(b);
  print(x);
  print(f);
}
rodeone2
źródło