Namespaces
Variants

C++ attribute: likely, unlikely (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Attributes
(C++23)
(C++11) (until C++26)
(C++14)
likely
(C++20)
(C++17)
(C++11)
unlikely
(C++20)

允许编译器对包含该语句的执行路径比不包含该语句的替代执行路径更可能或更不可能的情况进行优化。

目录

语法

[ [ likely ] ] (1)
[ [ unlikely ] ] (2)

说明

这些属性可应用于标签和语句(除声明语句外)。它们不能同时应用于同一标签或语句。

1) 适用于语句,允许编译器对包含该语句的执行路径进行优化,该路径的发生概率被认为高于不包含此语句的任何替代执行路径。
2) 适用于语句,允许编译器对包含该语句的执行路径比不包含该语句的替代执行路径可能性更低的情况进行优化。

当且仅当执行路径包含跳转至某个标签时,该执行路径才被视为包含该标签:

int f(int i)
{
    switch (i)
    {
        case 1: [[fallthrough]];
        [[likely]] case 2: return 1;
    }
    return 2;
}

i == 2 被认为比其他任何 i 值更可能出现,但 [ [ likely ] ] i == 1 的情况没有影响,即使它贯穿了 case 2 : 标签。

示例

#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <random>
namespace with_attributes
{
    constexpr double pow(double x, long long n) noexcept
    {
        if (n > 0) [[likely]]
            return x * pow(x, n - 1);
        else [[unlikely]]
            return 1;
    }
    constexpr long long fact(long long n) noexcept
    {
        if (n > 1) [[likely]]
            return n * fact(n - 1);
        else [[unlikely]]
            return 1;
    }
    constexpr double cos(double x) noexcept
    {
        constexpr long long precision{16LL};
        double y{};
        for (auto n{0LL}; n < precision; n += 2LL) [[likely]]
            y += pow(x, n) / (n & 2LL ? -fact(n) : fact(n));
        return y;
    }
} // namespace with_attributes
namespace no_attributes
{
    constexpr double pow(double x, long long n) noexcept
    {
        if (n > 0)
            return x * pow(x, n - 1);
        else
            return 1;
    }
    constexpr long long fact(long long n) noexcept
    {
        if (n > 1)
            return n * fact(n - 1);
        else
            return 1;
    }
    constexpr double cos(double x) noexcept
    {
        constexpr long long precision{16LL};
        double y{};
        for (auto n{0LL}; n < precision; n += 2LL)
            y += pow(x, n) / (n & 2LL ? -fact(n) : fact(n));
        return y;
    }
} // namespace no_attributes
double gen_random() noexcept
{
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_real_distribution<double> dis(-1.0, 1.0);
    return dis(gen);
}
volatile double sink{}; // 确保产生副作用
int main()
{
    for (const auto x : {0.125, 0.25, 0.5, 1. / (1 << 26)})
        std::cout
            << std::setprecision(53)
            << "x = " << x << '\n'
            << std::cos(x) << '\n'
            << with_attributes::cos(x) << '\n'
            << (std::cos(x) == with_attributes::cos(x) ? "equal" : "differ") << '\n';
    auto benchmark = [](auto fun, auto rem)
    {
        const auto start <span

参考文献

  • C++23 标准 (ISO/IEC 14882:2024):
  • 9.12.7 可能性属性 [dcl.attr.likelihood]
  • C++20 标准 (ISO/IEC 14882:2020):
  • 9.12.6 可能性属性 [dcl.attr.likelihood]