Поиск…
замечания
В ноябре 2014 года Комитет по стандартизации С ++ принял предложение N3922, которое устраняет правило исключения специального типа для автоматических и согласованных инициализаторов с использованием прямого синтаксиса инициализации. Это не является частью стандарта C ++, но было реализовано некоторыми компиляторами.
Вычисление параметра шаблона для конструкторов
До C ++ 17 вычитание шаблона не может вывести тип класса для вас в конструкторе. Он должен быть явно указан. Иногда, однако, эти типы могут быть очень громоздкими или (в случае лямбда), которые невозможно назвать, поэтому мы получили распространение типов фабрик (таких как make_pair()
, make_tuple()
, back_inserter()
и т. Д.).
Это больше не нужно:
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)>
Считается, что конструкторы выводят параметры шаблона класса, но в некоторых случаях этого недостаточно, и мы можем предоставить явные инструкции для вычитания:
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>
Выделение типа шаблона
Синтаксис шаблонов
template<typename T>
void f(ParamType param);
f(expr);
Случай 1: ParamType
является ссылкой или указателем, но не универсальной или прямой ссылкой. В этом случае подобная дедукция работает таким образом. Компилятор игнорирует ссылочную часть, если она существует в expr
. Затем компилятор шаблонов совпадение expr
типа «ы против ParamType
к определившим 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&
Случай 2: ParamType
является универсальной ссылкой или прямой ссылкой. В этом случае вывод типа такой же, как в случае 1, если expr
является значением r. Если expr
является lvalue, то и T
и ParamType
выводятся как значения lvalue.
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&&
Случай 3: ParamType
- это ни указатель, ни ссылка. Если expr
является ссылкой, эталонная часть игнорируется. Если expr
является const, это также игнорируется. Если он является volatile, который также игнорируется при выводе типа T.
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
работает почти так же, как и выделение типа шаблона. Ниже приведены несколько примеров:
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&&
Ниже перечислены различия:
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>
Как вы можете видеть, используете ли вы принудительные инициализаторы, auto принудительно создает переменную типа std::initializer_list<T>
. Если он не может вывести T
, код отклоняется.
Когда auto
используется как возвращаемый тип функции, он указывает, что функция имеет возвращаемый тип возврата .
auto f() -> int {
return 42;
}
C ++ 14 позволяет, помимо использования авто разрешенных в C ++ 11, следующих:
При использовании в качестве возвращаемого типа функции без возвращаемого возвращаемого типа указывает, что тип возвращаемого значения функции должен выводиться из операторов return в теле функции, если таковые имеются.
// f returns int: auto f() { return 42; } // g returns void: auto g() { std::cout << "hello, world!\n"; }
При использовании в типе параметра лямбда определяется лямбда как общая лямбда .
auto triple = [](auto x) { return 3*x; }; const auto x = triple(42); // x is a const int with value 126
Специальная форма decltype(auto)
выводит тип, используя правила вывода типа decltype
а не auto
.
int* p = new int(42);
auto x = *p; // x has type int
decltype(auto) y = *p; // y is a reference to *p
В C ++ 03 и ранее ключевое слово auto
имело совершенно иное значение как спецификатор класса хранения, который был унаследован от C.