Espacios de nombres
Variantes

atributo de C++: likely, unlikely (desde C++20)

De cppreference.com
 
 
 
 
 

Permite al compilador optimizar para el caso en el que las rutas de ejecución que incluyen esa declaración son más o menos probables que cualquier ruta de ejecución alterna que no incluya dicha declaración.

Sintaxis

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

Explicación

Estos atributos pueden aplicarse a etiquetas y declaraciones (que no sean instrucciones de declaración). No pueden aplicarse simultáneamente a la misma etiqueta o declaración.

1) Se aplica a una instrucción para permitir al compilador optimizar para el caso en el que las rutas de ejecución que incluyen esa declaración son más probables que cualquier ruta alterna de ejecución que no incluya dicha declaración.
2) Se aplica a una instrucción para permitir al compilador optimizar para el caso en el que las rutas de ejecución que incluyen esa declaración son menos probables que cualquier ruta de ejecución alterna que no incluya dicha declaración.

Se considera que una ruta de ejecución incluye una etiqueta si y solo si contiene un salto a esa etiqueta:

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

i == 2 se considera más probable que cualquier otro valor de i, pero [[likely]] no tiene ningún efecto sobre el caso i == 1 a pesar de que cae a través de la etiqueta case 2:.

Ejemplo

#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <random>

namespace con_atributos {
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;
}
}  // espacio de nombre con_atributos

namespace sin_atributos {
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;
}
}  // espacio de nombres sin atributos

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{}; // asegura un efecto secundario

int main() {
    for (const auto x : {0.125, 0.25, 0.5, 1. / (2 << 25)}) {
        std::cout
            << std::setprecision(53)
            << "x = " << x << '\n'
            << std::cos(x) << '\n'
            << con_atributos::cos(x) << '\n'
            << (std::cos(x) == con_atributos::cos(x) ? "igual" : "diferente") << '\n';
    }

auto benchmark = [](auto fun, auto rem) {
        const auto start = std::chrono::high_resolution_clock::now();
        for (auto size{1ULL}; size != 10000000ULL; ++size) {
            sink = fun(gen_random());
        }
        const std::chrono::duration<double> diff =
            std::chrono::high_resolution_clock::now() - start;
        std::cout << "Tiempo: " << std::fixed << std::setprecision(6) << diff.count()
                  << " seg " << rem << std::endl;
    };

    benchmark(con_atributos::cos, "(con atributos:)");
    benchmark(sin_atributos::cos, "(sin atributos)");
    benchmark(cos, "(std::cos)");
}

Posible salida:

x = 0.125
0.99219766722932900560039115589461289346218109130859375
0.99219766722932900560039115589461289346218109130859375
igual
x = 0.25
0.96891242171064473343022882545483298599720001220703125
0.96891242171064473343022882545483298599720001220703125
igual
x = 0.5
0.8775825618903727587394314468838274478912353515625
0.8775825618903727587394314468838274478912353515625
igual
x = 1.490116119384765625e-08
0.99999999999999988897769753748434595763683319091796875
0.99999999999999988897769753748434595763683319091796875
igual
Tiempo: 0.579122 seg (con atributos:)
Tiempo: 0.722553 seg (sin atributos)
Tiempo: 0.425963 seg (std::cos)