C++ attribute: likely, unlikely (since C++20)
From cppreference.com
 
 
 < cpp | language | attributes 
 
 
 C++ 
 Feature test macros (C++20)
 Concepts library (C++20)
 Metaprogramming library (C++11)
 Ranges library (C++20)
 Filesystem library (C++17)
 Concurrency support library (C++11)
 Execution control library (C++26)
C++ language 
 
  
  
 General topics
 Conditional execution statements
 Iteration statements (loops)
 Jump statements
 Dynamic exception specifications (until C++17*)
noexcept specifier (C++11) Exceptions
 Namespaces
 Types
 Specifiers
 User-defined (C++11)
 Utilities
 Attributes (C++11)
 Types
 Type alias declaration (C++11)
 Casts
 Memory allocation
 Class-specific function properties
 Special member functions
 Miscellaneous
Declarations 
 
 
 
 
 
 
 
 
 
 Overview
 Specifiers
(C++11)
(C++20)
(C++20)
 Translation-unit-local (C++20)
(C++11)
(C++11)
(C++11)
 Pack indexing specifier (C++26)    
 Attributes (C++11)
 Declarators
 Block declarations
   →Structured binding declaration (C++17)
 Alias declaration (C++11)
 static_assert declaration (C++11)
 Opaque enum declaration (C++11)
 Other declarations
 Explicit template instantiation (C++11)
 Attribute declaration (C++11)
Attributes 
 
 
 
 
 
 
 
 
 
 
 
 
(C++23)
(C++11)(until C++26)
(C++14)
(C++17)
(C++26)
likely
(C++20)
(C++17)
(C++17)
(C++11)
(C++20)
(TM TS)
unlikely
(C++20)
Allow the compiler to optimize for the case where paths of execution including that statement are more or less likely than any alternative path of execution that does not include such a statement.
Contents
[edit] Syntax
[[likely]]
 (1)
 
[[unlikely]]
 (2)
 
[edit] Explanation
These attributes may be applied to labels and statements (other than declaration-statements). They may not be simultaneously applied to the same label or statement.
1) Applies to a statement to allow the compiler to optimize for the case where paths of execution including that statement are more likely than any alternative path of execution that does not include such a statement.
2) Applies to a statement to allow the compiler to optimize for the case where paths of execution including that statement are less likely than any alternative path of execution that does not include such a statement.
A path of execution is deemed to include a label if and only if it contains a jump to that label:
int f(int i) { switch (i) { case 1: [[fallthrough]]; [[likely]] case 2: return 1; } return 2; }
i == 2 is considered more likely than any other value of i, but the [[likely]] has no effect on the i == 1 case even though it falls through the case 2: label.
[edit] Example
Run this code
#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{}; // ensures a side effect 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 = std::chrono::high_resolution_clock::now (); for (auto size{1ULL}; size != 10'000'000ULL; ++size) sink = fun(gen_random()); const std::chrono::duration <double> diff = std::chrono::high_resolution_clock::now () - start; std::cout << "Time: " << std::fixed << std::setprecision (6) << diff.count() << " sec " << rem << std::endl ; }; benchmark(with_attributes::cos, "(with attributes)"); benchmark(no_attributes::cos, "(without attributes)"); benchmark([](double t) { return std::cos (t); }, "(std::cos)"); }
Possible output:
x = 0.125 0.99219766722932900560039115589461289346218109130859375 0.99219766722932900560039115589461289346218109130859375 equal x = 0.25 0.96891242171064473343022882545483298599720001220703125 0.96891242171064473343022882545483298599720001220703125 equal x = 0.5 0.8775825618903727587394314468838274478912353515625 0.8775825618903727587394314468838274478912353515625 equal x = 1.490116119384765625e-08 0.99999999999999988897769753748434595763683319091796875 0.99999999999999988897769753748434595763683319091796875 equal Time: 0.579122 sec (with attributes) Time: 0.722553 sec (without attributes) Time: 0.425963 sec (std::cos)
[edit] References
- C++23 standard (ISO/IEC 14882:2024):
- 9.12.7 Likelihood attributes [dcl.attr.likelihood]
 
- C++20 standard (ISO/IEC 14882:2020):
- 9.12.6 Likelihood attributes [dcl.attr.likelihood]