Spec-Zone.ru › C++

Заменители типов спецификаторов (с C++11)

Для переменных, указывает, что тип переменной, которая объявляется, будет автоматически выведен из её инициализатора.

Для функций, указывает, что возвращаемый тип будет выведен из её операторов возврата.

(с C++14)

Для нетиповых параметров шаблонов, указывает, что тип будет выведен из аргумента.

(с C++17)

Синтаксис

ограничение типа (необязательно) auto (1) (с C++11)
ограничение типа (необязательно) decltype ( auto ) (2) (с C++14)
ограничение типа - (с C++20) имя концепции, необязательно с квалификатором, необязательно с последующим списком аргументов шаблона, заключённым в <>
1) тип выводится по правилам вывода аргументов шаблона.
2) тип является decltype(expr), где expr — это инициализатор или используемые в операторах возврата.

Заполнитель auto может сопровождаться модификаторами, такими как const или &, которые будут участвовать в выводе типа. Заполнитель decltype(auto) должен быть единственным элементом объявленного типа.(с C++14)

Объяснение

Заполнитель типа может появляться в следующих контекстах:

  • в последовательности спецификаторов типа переменной: auto x = expr; как спецификатор типа. Тип выводится из инициализатора.
    Если заполнитель типа — auto или ограничение типа auto(с C++20), тип переменной выводится из инициализатора по правилам вывода аргументов шаблона из вызова функции (см. вывод аргументов шаблона — другие контексты для деталей).
    Например, при const auto& i = expr;, тип i — это точно тип аргумента u в воображаемом шаблоне template<class U> void f(const U& u) , если вызов функции f(expr) был скомпилирован. Поэтому auto&& может быть выведен как ссылка на lvalue или rvalue ссылку в соответствии с инициализатором, который используется в цикле for, основанном на диапазоне.

    Если заполнитель типа — decltype(auto) или ограничение типа decltype(auto)(с C++20), выведенный тип — decltype(expr), где expr — инициализатор.

    (с C++14)

    Если заполнитель типа используется для объявления нескольких переменных, выведенные типы должны совпадать. Например, объявление auto i = 0, d = 0.0; некорректно, а объявление auto i = 0, *p = &i; корректно, и auto выводится как int.

  • в type-id выражения new. Тип выводится из инициализатора. Для new T init (где T содержит заполнитель типа, init — это либо инициализатор в скобках, либо список инициализаторов в фигурных скобках), тип T выводится так же, как для переменной x в выдуманном объявлении T x init;.
  • (с C++14) в возвращаемом типе функции или лямбда-выражения: auto& f();. Возвращаемый тип выводится из операнда его не-отбрасываемого(с C++17) оператора return.
    См. функция — вывод возвращаемого типа.
  • (с C++17) в объявлении параметра нетипового параметра шаблона: template<auto I> struct A;. Его тип выводится из соответствующего аргумента.

Запись auto также может появиться в спецификаторе простого типа явного преобразования типа: auto(expr) и auto{expr}. Его тип выводится из выражения.

(с C++23)

Кроме того, auto и ограничение типа auto(с C++20) могут появляться в:

  • объявлении параметра лямбда-выражения: [](auto&&){}. Такое лямбда-выражение — шаблонный лямбда-выражение.
  • (с C++20) объявлении параметра функции: void f(auto);. Объявление функции вводит сокращённый шаблон функции.
(с C++14)

Ограничение типа

Если ограничение типа присутствует, пусть T — это выведенный тип для заполнителя, ограничение типа вводит выражение ограничения следующим образом:

  • Если ограничение типа — Concept<A1, ..., An>, то выражение ограничения — Concept<T, A1, ..., An>;
  • в противном случае (ограничение типа — Concept без списка аргументов), выражение ограничения — Concept<T>.

Вывод терпит неудачу, если выражение ограничения некорректно или возвращает false.

(с C++20)

Примечания

До C++11 auto имел семантику спецификатора длительности хранения.

Смешивание auto переменных и функций в одном объявлении, как в auto f() -> int, i = 0; не допускается.

Заполнитель auto может также использоваться с функцией-декларатором, за которым следует возвращаемый тип, в этом случае объявленный возвращаемый тип — это тот возвращаемый тип (который снова может быть заполнителем типа).

auto (*p)() -> int; // declares p as pointer to function returning int
auto (*q)() -> auto = p; // declares q as pointer to function returning T
                         // where T is deduced from the type of p

Заполнитель auto также может использоваться в объявлении структурированного связывания.

(с C++17)

Ключевое слово auto также может использоваться в nested-name-specifier. Nested-name-specifier вида auto:: — это заполнитель, который заменяется типом класса или перечисления по правилам вывода заполнителей ограниченного типа.

(концепции TS)
Макрос проверки возможностей Значение Std Функция
__cpp_decltype_auto 201304L (C++14) decltype(auto)

Пример

#include <iostream>
#include <utility>
 
template<class T, class U>
auto add(T t, U u) { return t + u; } // the return type is the type of operator+(T, U)
 
// perfect forwarding of a function call must use decltype(auto)
// in case the function it calls returns by reference
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}
 
template<auto n> // C++17 auto parameter declaration
auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list
{
    return {n, n};
}
 
int main()
{
    auto a = 1 + 2;          // type of a is int
    auto b = add(1, 1.2);    // type of b is double
    static_assert(std::is_same_v<decltype(a), int>);
    static_assert(std::is_same_v<decltype(b), double>);
 
    auto c0 = a;             // type of c0 is int, holding a copy of a
    decltype(auto) c1 = a;   // type of c1 is int, holding a copy of a
    decltype(auto) c2 = (a); // type of c2 is int&, an alias of a
    std::cout << "before modification through c2, a = " << a << '\n';
    ++c2;
    std::cout << " after modification through c2, a = " << a << '\n';
 
    auto [v, w] = f<0>(); //structured binding declaration
 
    auto d = {1, 2}; // OK: type of d is std::initializer_list<int>
    auto n = {5};    // OK: type of n is std::initializer_list<int>
//  auto e{1, 2};    // Error as of DR n3922, std::initializer_list<int> before
    auto m{5};       // OK: type of m is int as of DR n3922, initializer_list<int> before
//  decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression
 
    // auto is commonly used for unnamed types such as the types of lambda expressions
    auto lambda = [](int x) { return x + 3; };
 
//  auto int x; // valid C++98, error as of C++11
//  auto x;     // valid C, error in C++
 
    [](...){}(c0, c1, v, w, d, n, m, lambda); // suppresses "unused variable" warnings
}

Возможный вывод:

before modification through c2, a = 3
 after modification through c2, a = 4

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющих поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение, как опубликовано Правильное поведение
CWG 1265 C++11 спецификатор auto мог использоваться для объявления функции с возвращаемым типом в конце и определения переменной в одном операторе объявления запрещено
CWG 1346 C++11 список выражений в скобках не мог быть присвоен переменной типа auto разрешено
CWG 1347 C++11 объявление со спецификатором auto могло определить две переменные
с типами T и std::initializer_list<T> соответственно
запрещено
CWG 1852 C++14 спецификатор auto в decltype(auto) также был плейсхолдером не является плейсхолдером в данном случае

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/auto

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API