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 isautoor 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 ofiis exactly the type of the argumentuin 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), whereeis 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 theautois 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