Sök…
Anmärkningar
I november 2014 antog C ++ standardiseringskommittén förslag N3922, vilket eliminerar den särskilda avdragsregeln för auto- och avstängda initialiseringar med syntax för direktinitiering. Detta är inte en del av C ++ -standarden men har implementerats av vissa kompilatorer.
Avdrag för mallparameter för konstruktörer
Innan C ++ 17 kan mallavdrag inte dra av klasstypen för dig i en konstruktör. Det måste anges uttryckligen. Ibland kan emellertid dessa typer vara mycket besvärliga eller (i fallet med lambdas) omöjliga att namnge, så vi fick en spridning av make_pair()
som make_pair()
, make_tuple()
, back_inserter()
, etc.).
Detta är inte längre nödvändigt:
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)>
Konstruktörer anses härleda klassens mallparametrar, men i vissa fall är detta otillräckligt och vi kan tillhandahålla tydliga avdragsguider:
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>
Malltyp Avdrag
Mall generisk syntax
template<typename T>
void f(ParamType param);
f(expr);
Fall 1: ParamType
är en referens eller pekare, men inte en universell eller framåtreferens. I detta fall fungerar typavdrag på detta sätt. Kompilatorn ignorerar referensdelen om den finns i expr
. Kompilatorn matchar sedan mönster från expr
mot ParamType
och bestämmer T
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
är en universell referens eller framåtreferens. I detta fall är expr
detsamma som i fall 1 om expr
är en ränta. Om expr
är en lvalue, ParamType
både T
och ParamType
till att vara lvalue-referenser.
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
är varken en pekare eller en referens. Om expr
är en referens ignoreras referensdelen. Om expr
är const så ignoreras också. Om det är flyktigt som också ignoreras när man drar av T: s typ.
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
Auto Type Deduction
Typavdrag med hjälp av auto
nyckelordet fungerar nästan samma som Avdrag för malltyp. Nedan följer några exempel:
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&&
Skillnaderna anges nedan:
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>
Som du kan se om du använder avstängda initialiseringar tvingas auto att skapa en variabel av typen std::initializer_list<T>
. Om den inte kan dra av T
, avvisas koden.
När auto
används som returtyp för en funktion, anger den att funktionen har en bakre returtyp .
auto f() -> int {
return 42;
}
C ++ 14 tillåter, förutom användningen av auto tillåtna i C ++ 11, följande:
När den används som returtyp för en funktion utan släpningstyp, anger du att funktionens returtyp ska härledas från returrätten i funktionens kropp, om någon.
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
När den används i parametertypen för en lambda, definierar den lambda som en generisk lambda .
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
Den speciella formen decltype(auto)
drar en typ med hjälp av decltype
för decltype
snarare än för auto
.
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
I C ++ 03 och tidigare hade auto
nyckelordet en helt annan betydelse som en lagringsklassspecifikator som ärvdes från C.