placeholder type specifiers (since C++11)
For variables, specifies that the type of the variable that is being declared will be automatically deduced from its initializer.
For functions, specifies that the return type will be deduced from its return statements. | (since C++14) |
For non-type template parameters, specifies that the type will be deduced from the argument. | (since C++17) |
Syntax
auto | (1) | (since C++11) |
decltype(auto) | (2) | (since C++14) |
type-constraint auto | (3) | (since C++20) |
type-constraint decltype(auto) | (4) | (since C++20) |
type-constraint | - | a concept name, optionally qualified, optionally followed by a template argument list enclosed in <> |
The placeholder auto
may be accompanied by modifiers, such as const
or &
, which will participate in the type deduction. The placeholder decltype(auto)
must be the the sole constituent of the declared type. (since C++14).
Explanation
A placeholder type specifier may appear in the following contexts:
- in the type specifier of a variable:
auto x = expr;
. The type is deduced from the initializer.
If the placeholder type specifier isauto
or type-constraintauto
(since C++20), the variable type is deduced from the initializer using the rules for template argument deduction from a function call (see template argument deduction#Other contexts for details).
For example, givenconst auto& i = expr;
, the type ofi
is exactly the type of the argumentu
in an imaginary templatetemplate<class U> void f(const U& u)
if the function callf(expr)
was compiled. Therefore,auto&&
may be deduced either as an lvalue reference or rvalue reference according to the initializer, which is used in range-based for loop.
If the placeholder type specifier is
decltype(auto)
or type-constraintdecltype(auto)
(since C++20), the deduced type isdecltype(e)
, wheree
is the initializer.(since C++14) If the placeholder type specifier is used to declare multiple variables, the deduced types must match. For example, the declaration
auto i = 0, d = 0.0;
is ill-formed, while the declarationauto i = 0, *p = &i;
is well-formed and theauto
is deduced asint
. - in the type-id of a new expression. The type is deduced from the initializer. For
new T init
(where T contains a placeholder type, init is either a parenthesized initializer or a brace-enclosed initializer list), the type of T is deduced as if for variable x in the invented declarationT x init;
. - (since C++14) in the return type of a function or lambda expression:
auto& f();
. The return type is deduced from the operand of its non-discarded (since C++17) return statement.
See function#Return_type_deduction. - (since C++17) in the parameter declaration of a non-type template parameter:
template<auto I> struct A;
. Its type is deduced from the corresponding argument.
Furthermore,
| (since C++14) |
If type-constraint is present, let
| (since C++20) |
Notes
Until C++11, auto
had the semantic of a storage duration specifier.
Mixing auto
variables and functions in one declaration, as in auto f() -> int, i = 0;
is not allowed.
The auto
specifier may also be used with a function declarator that is followed by a trailing return type, in which case the declared return type is that trailing return type (which may again be a placeholder type).
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
The | (since C++17) |
The | (concepts TS) |
Example
#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 << "a, before modification through c2 = " << a << '\n'; ++c2; std::cout << "a, after modification through c2 = " << 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 C++17, std::initializer_list<int> before auto m{5}; // OK: type of m is int as of C++17, 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++ }
Possible output:
a, before modification through c2 = 3 a, after modification through c2 = 4
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/auto