Suche…
Bemerkungen
Im November 2014 verabschiedete das C ++ Standardization Committee den Vorschlag N3922, der die spezielle Typabzugsregel für Auto- und Braced-Initialisierer mit direkter Initialisierungssyntax beseitigt. Dies ist nicht Teil des C ++ - Standards, wurde jedoch von einigen Compilern implementiert.
Vorlagenparameterabzug für Konstruktoren
Vor C ++ 17 kann ein Vorlagenabzug den Klassentyp für Sie nicht in einem Konstruktor ableiten. Es muss explizit angegeben werden. Manchmal können diese Typen jedoch sehr umständlich sein oder (im Fall von Lambdas) nicht benannt werden. make_pair()
wir eine make_pair()
make_tuple()
wie make_pair()
, make_tuple()
, back_inserter()
usw.) erhalten.
Das ist nicht mehr nötig:
std::pair p(2, 4.5); // std::pair<int, double>
std::tuple t(4, 3, 2.5); // std::tuple<int, int, double>
std::copy_n(vi1.begin(), 3,
std::back_insert_iterator(vi2)); // constructs a back_insert_iterator<std::vector<int>>
std::lock_guard lk(mtx); // std::lock_guard<decltype(mtx)>
Es wird angenommen, dass Konstruktoren die Klassenvorlagenparameter ableiten. In einigen Fällen reicht dies jedoch nicht aus, und wir können explizite Abzugshilfen bereitstellen:
template <class Iter>
vector(Iter, Iter) -> vector<typename iterator_traits<Iter>::value_type>
int array[] = {1, 2, 3};
std::vector v(std::begin(array), std::end(array)); // deduces std::vector<int>
Vorlagentyp Abzug
Generische Vorlagen-Syntax
template<typename T>
void f(ParamType param);
f(expr);
Fall 1: ParamType
ist eine Referenz oder ein Zeiger, jedoch keine Universal- oder Weiterleitungsreferenz. In diesem Fall funktioniert der Typabzug auf diese Weise. Der Compiler ignoriert den Referenzteil, wenn er in expr
. Der Compiler expr
den Typ von ParamType
mit ParamType
und der Bestimmung von T
ParamType
.
template<typename T>
void f(T& param); //param is a reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T is int, param's type is int&
f(cx); // T is const int, param's type is const int&
f(rx); // T is const int, param's type is const int&
Fall 2: ParamType
ist eine Universalreferenz oder ParamType
. In diesem Fall ist der expr
derselbe wie in Fall 1, wenn der expr
ein r- expr
ist. Wenn expr
ein lvalue ist, werden sowohl T
als auch ParamType
als lvalue-Referenzen abgeleitet.
template<typename T>
void f(T&& param); // param is a universal reference
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // x is lvalue, so T is int&, param's type is also int&
f(cx); // cx is lvalue, so T is const int&, param's type is also const int&
f(rx); // rx is lvalue, so T is const int&, param's type is also const int&
f(27); // 27 is rvalue, so T is int, param's type is therefore int&&
Fall 3: ParamType
ist weder ein Zeiger noch eine Referenz. Wenn expr
eine Referenz ist, wird der Referenzteil ignoriert. Wenn expr
const ist, wird dies ebenfalls ignoriert. Wenn es flüchtig ist, wird es auch ignoriert, wenn der Typ von T abgeleitet wird.
template<typename T>
void f(T param); // param is now passed by value
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
Automatischer Typabzug
Der Typabzug mit dem Schlüsselwort auto
funktioniert fast genauso wie der Abzug des Vorlagentyps. Nachfolgend einige Beispiele:
auto x = 27; // (x is neither a pointer nor a reference), x's type is int
const auto cx = x; // (cx is neither a pointer nor a reference), cs's type is const int
const auto& rx = x; // (rx is a non-universal reference), rx's type is a reference to a const int
auto&& uref1 = x; // x is int and lvalue, so uref1's type is int&
auto&& uref2 = cx; // cx is const int and lvalue, so uref2's type is const int &
auto&& uref3 = 27; // 27 is an int and rvalue, so uref3's type is int&&
Die Unterschiede sind nachfolgend aufgeführt:
auto x1 = 27; // type is int, value is 27
auto x2(27); // type is int, value is 27
auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 }; // type is std::initializer_list<int>, value is { 27 }
// in some compilers type may be deduced as an int with a
// value of 27. See remarks for more information.
auto x5 = { 1, 2.0 } // error! can't deduce T for std::initializer_list<t>
Wie Sie sehen, wenn Sie geschweifte Initialisierer verwenden, wird auto dazu gezwungen, eine Variable vom Typ std::initializer_list<T>
zu erstellen. Wenn der T
, wird der Code abgelehnt.
Wenn auto
als Rückgabetyp einer Funktion verwendet wird, wird angegeben, dass die Funktion einen nachgestellten Rückgabetyp hat .
auto f() -> int {
return 42;
}
C ++ 14 erlaubt zusätzlich zu den in C ++ 11 zugelassenen Verwendungen von auto Folgendes:
Bei Verwendung als Rückgabetyp einer Funktion ohne nachgestellten Rückgabetyp wird angegeben, dass der Rückgabetyp der Funktion aus den Rückgabeanweisungen im Rumpf der Funktion (sofern vorhanden) abgeleitet werden soll.
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
Bei Verwendung im Parametertyp eines Lambda wird das Lambda als generisches Lambda definiert .
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
Das spezielle Formular decltype(auto)
leitet einen Typ unter Verwendung der decltype
von decltype
und nicht von auto
.
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
In C ++ 03 und früheren Versionen hatte das Schlüsselwort auto
eine völlig andere Bedeutung als ein von C geerbter Speicherklassenspezifizierer .