命名空间
变体
操作

占位符类型说明符 (since C++11)

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
range-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

占位符类型说明符指定一个占位符类型,该类型稍后将被替换,通常是通过从初始化器推导而来。

内容

[编辑] 语法

类型约束 (可选) auto (1)
类型约束 (可选) decltype(auto) (2) (自 C++14 起)
类型约束 - (since C++20) 概念 名称,可选地限定,可选地后跟括在 <> 中的模板实参列表
1) 类型使用 模板实参推导 的规则推导。
2) 类型为 decltype(expr),其中 expr 是初始化器或返回语句中使用的。

占位符 auto 可以伴随修饰符,例如 const&,它们将参与类型推导。占位符 decltype(auto) 必须是声明类型的唯一组成部分。(自 C++14 起)

如果存在 类型约束,设 T 为为占位符推导的类型,则 类型约束 引入 约束表达式 如下

  • 如果 类型约束Concept<A1, ..., An>,则约束表达式为 Concept<T, A1, ..., An>
  • 否则(类型约束 是没有实参列表的 Concept),约束表达式为 Concept<T>

如果约束表达式无效或返回 false,则推导失败。

(自 C++20 起)

[编辑] 解释

占位符类型说明符可能出现在以下上下文中

形参声明

在以下形参声明中,声明的形参类型可以是语法 (1)

  • 如果 lambda 表达式 的形参具有占位符类型,则 lambda 表达式是泛型 lambda。
(自 C++14 起)
(自 C++17 起)
(自 C++20 起)

[编辑] 函数声明

占位符类型可以出现在包含尾随返回类型的 函数声明符声明说明符中。

占位符类型可以出现在 函数声明符 的声明返回类型中的声明说明符或类型说明符中。在这种情况下,将应用返回类型推导

(自 C++14 起)
auto f() -> int; // OK: f returns int
auto g() { return 0.0; } // OK since C++14: g returns double
auto h(); // OK since C++14: h’s return type will be deduced when it is defined

[编辑] 变量声明

使用占位符类型声明的变量的类型从其初始化器推导而来。此用法在变量的初始化声明中是允许的。

占位符类型只能作为声明说明符序列中的声明说明符之一出现,或者作为指定替换此类声明说明符的类型的尾随返回类型中的类型说明符之一出现。在这种情况下,声明必须声明至少一个变量,并且每个变量都必须具有非空初始化器。

// “auto”s in declaration specifiers
auto x = 5; // OK: x has type int
const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int
static auto y = 0.0; // OK: y has type double
 
auto f() -> int;
auto (*fp)() -> auto = f; // OK: the “auto” in the trailing return type
                          // can be deduced from f

结构化绑定声明

auto 说明符可以用于结构化绑定声明。

(自 C++17 起)

[编辑] new 表达式

占位符类型可以用于 new 表达式 的 type-id 的类型说明符序列中。在此类 type-id 中,占位符类型必须作为类型说明符序列中的类型说明符之一或指定替换此类类型说明符的类型的尾随返回类型出现。

函数式转型

auto 类型说明符可以用作函数式转型的类型说明符。

(自 C++23 起)

[编辑] 注解

在 C++11 之前,auto 具有存储期说明符的语义。

在上面未明确声明的上下文中使用占位符类型的程序是非良构的。

如果声明声明了多个实体,并且声明说明符序列使用了占位符类型,则如果满足以下任何条件,则程序是非良构的

  • 声明的某些实体不是变量。
  • 在每次推导中,替换占位符类型的类型都不相同。
auto f() -> int, i = 0; // Error: declares a function and a variable with “auto”
auto a = 5, b = {1, 2}; // Error: different types for “auto”

auto 关键字也可以在嵌套名称说明符中使用。形式为 auto:: 的嵌套名称说明符是一个占位符,它被遵循 约束类型 占位符推导规则的类或枚举类型替换。

(概念 TS)
特性测试宏 Std 特性
__cpp_decltype_auto 201304L (C++14) decltype(auto)

[编辑] 关键字

auto, decltype

[编辑] 示例

#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 说明符的声明可以定义两个变量
类型分别为 Tstd::initializer_list<T>
禁止
CWG 1852 C++14 auto 说明符在 decltype(auto) 中也是一个占位符 不是占位符
在这种情况下
CWG 1892 C++11 函数指针类型 id 的返回类型可以是 auto 禁止
CWG 2476 C++11 CWG 问题 1892 的解决方案禁止推导
来自初始化器的函数指针变量的返回类型
允许

[编辑] 参考

  • C++23 标准 (ISO/IEC 14882:2024)
  • 9.2.9.6 占位符类型说明符 [dcl.spec.auto]
  • C++20 标准 (ISO/IEC 14882:2020)
  • 9.2.8.5 占位符类型说明符 [dcl.spec.auto]
  • C++17 标准 (ISO/IEC 14882:2017)
  • 10.1.7.4 auto 说明符 [dcl.spec.auto]
  • C++14 标准 (ISO/IEC 14882:2014)
  • 7.1.6.4 auto 说明符 [dcl.spec.auto]
  • C++11 标准 (ISO/IEC 14882:2011)
  • 7.1.6.4 auto 说明符 [dcl.spec.auto]