C++ 属性: assume (C++23 起)

来自cppreference.com
< cpp‎ | language‎ | attributes

指示表达式在给定的位置永远会求值为 true

语法

[[assume( 表达式 )]]
表达式 - 必须求值为 true 的表达式

解释

只能应用到空语句,例如 [[assume(x > 0)]];。该语句被称为 假设 。如果该表达式(按语境转换到 bool)不会在假设处求值为 true,那么行为未定义。否则该语句什么也不会做。特别注意该表达式不会求值(但它依然会潜在求值)。

假设的目的是允许编译器根据已有的信息进行优化。

表达式 不能是逗号表达式,但是可以通过外面包围一层圆括号来使用逗号表达式。

注解

如果表达式的行为未定义或者会导致异常抛出,那么它不会求值为 true

因为假设在不成立时会导致未定义行为,所以不能经常使用它们。它们不是用来提供函数的前提条件文档或者诊断是否违反前提条件的。另外,不要无条件假设编译器实际会用到哪些假设。

示例

void f(int& x, int y)
{
    void g(int);
    void h();
 
    [[assume(x > 0)]]; // 编译器可以假设 x 是正数
 
    g(x / 2); // 可以生成更高效的代码
 
    x = 3;
    int z = x;
 
    [[assume((h(), x == z))]]; // 编译器可以假设在调用 h 后 x 的值保持相同
                               // 该假设本身不会调用 h
 
    h();
    g(x); // 编译器可以用 g(3); 替换该语句
 
    h();
    g(x); // 编译器不能用 g(3); 替换该语句
          // 假设只在它出现的地方适用
 
    z = std::abs(y);
 
    [[assume((g(z), true))]]; // 编译器可以假设 g(z) 会返回
 
    g(z); // 根据上面和下面的假设,编译器可以用 g(10); 替换该语句
 
    [[assume(y == -10)]]; // 这里 y != -10 的情况下行为未定义
 
    [[assume((x - 1) * 3 == 12]];
 
    g(x); // 编译器可以用 g(5); 替换该语句
}

引用

  • C++23 标准(ISO/IEC 14882:2023):
  • 9.12.3 Assumption attribute [dcl.attr.assume]

外部链接

  • Clang 语言扩展文档:__builtin_assume
  • Clang 属性参考文档:assume
  • MSVC 文档:内建 __assume
  • GCC 13 前没有内建假设,但是可以使用 __builtin_unreachable,许多情况下可以通过 if (!(expr)) { __builtin_unreachable(); } 达到类似 [[assume]] 的效果。然而这样会对 expr 求值,在求值有副作用或者需要花费较长时间的情况下会有明显影响。如果求值导致异常抛出或者函数永不返回,那么行为也会不同。
  • GCC 13 语言属性参考文档:__attribute__((assume(...)))

参见

标记执行的不可抵达点
(函数)