2024 年 4 月 Tokyo 会议后一些频道主认为有意思的 C++ 标准提案

P1061R8: Structured Bindings can introduce a Pack
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1061r8.html

允许结构化绑定引入 pack :

std::tuple<X, Y, Z> f();

auto [...xs] = f();           // OK
auto [x, ...rest] = f();      // OK
auto [x,y,z, ...rest] = f();  // OK
auto [x, ...rest, z] = f();   // OK


P2034R3: Partially Mutable Lambda Captures
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2034r3.pdf

允许分别将每个 lambda 捕获声明为 mutable 了:

auto a = [mutable x, y]() {
  x = 1;  // OK
  y = 2;  // Error
};


P2135R1: P2055R1: A Relaxed Guide to memory_order_relaxed
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2135r1.pdf

一篇科普性质文章,介绍 C++11 relaxed 内存序的原子操作的 out-of-thin-air 现象以及 read-from-untaken-branch 现象,以及如何在已有程序中识别潜在的相关问题

P2141R2: Aggregates are named tuples
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2141r2.html

std::get, std::tuple_element 以及 std::tuple_size 等实现 tuple protocol 的 STL 函数和 type traits 原生支持 aggregate 类型:

struct Foo { int x; double y; std::string z; };

Foo x{1, 2.0, "3"};
std::get<1>(x);  // Evaluate to 2.0
static_assert(std::is_same_v<
  std::string,
  typename std::tuple_element<2, Foo>::type
>);  // OK
static_assert(std::tuple_size<Foo> == 3);  // OK


P2747R2: constexpr placement new
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html

让 placement-new 成为 core constant expression

P2748R5: Disallow Binding a Returned Glvalue to a Temporary
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2748r5.html

当函数返回一个引用时,不再允许这个引用绑定到临时对象上,杜绝一类 use-after-free 缺陷:

const int &foo() {
  return 42;  // Ill-formed
}


P2988R4: std::optional<T&>
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2988r4.pdf

std::optional 引入 std::optional<T&> 特化,可以实现用 std::optional 上的 monadic 操作替换一堆空指针判断

逐步氧化起来了

P3166R0: Static Exception Specifications
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3166r0.html

又要搞大新闻,重新引入了之前被废弃的 throw 声明符,可以用于声明一个函数所能够抛出的所有可能的异常类型:

void throws_nothing() throw();  // Effectively `noexcept`
void throws_a_b() throw(A, B);  // throws_a_b can throw A or B
void throws_any() throw(...);   // throws_any may throw any exception


一个亮点是允许使用 throw(auto) 自动推导函数可能抛出的异常类型集合:

void foo() throw(auto) { /* ... */ }


与老式 throw 声明符的本质区别在于编译器会强制检查异常集合的正确性。如果函数带有 throw 声明符但却可能抛出没有通过 throw 声明符声明的异常,那么程序 ill-formed:

void foo() throw(A) {
  throws_a_b(); // Ill-formed: B is not listed above

  try {
    throws_a_b(); // Ill-formed: B is not caught
  }
  catch (A) {}

  try {
    throws_a_b(); // OK since B will be caught
  }
  catch (A) {}
  catch (B) {}
}


按照这样的设计编译器理论上可以把所有带有 throw 声明符的函数的异常路径算得明明白白,可以开始优化 try-catch 路径了(例如把 throw-catch 直接优化为 goto)。

P3176R0: The Oxford variadic comma
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3176r0.html

不再允许不带前导逗号的 ellipsis parameter :

void foo(int ...);  // Ill-formed
 
 
Back to Top