0Pricing
C++ Academy · Lección

Elección de objetos invocables

Lambdas frente a bind y punteros

Elección de objetos invocables es una lección gratuita de C++ Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C++ Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C++ Academy incluye 4 lecciones en total.

La caja de herramientas de los objetos invocables

C++ ofrece varias formas de pasar comportamiento: punteros a funciones, lambdas, functors, std::bind y std::function. Cada una se adapta a necesidades distintas.

  • La velocidad y la flexibilidad suelen estar en conflicto.
  • La legibilidad también importa.
#include <iostream>

int twice(int x) { return x * 2; }

int main() {
    int (*fp)(int) = twice;
    auto lam = [](int x) { return x * 2; };
    std::cout << fp(5) << ' ' << lam(5) << '\n';
    return 0;
}

Cuándo usar un puntero a función

Elija un puntero a función cuando necesite un callback pequeño y sin estado, y quiera compatibilidad con C o ausencia de sobrecoste.

#include <iostream>

void logMsg(const char* m) { std::cout << "LOG: " << m << '\n'; }

int main() {
    void (*handler)(const char*) = logMsg;
    handler("started");
    return 0;
}

Cuándo usar una lambda

Una lambda es la opción moderna predeterminada: es concisa, puede capturar estado y el compilador la inserta bien en plantillas y algoritmos.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Capturar estado en una lambda

Las lambdas capturan variables del entorno, algo que los punteros a funciones no pueden hacer, por lo que son ideales para callbacks que dependen del contexto.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 3;
    std::vector<int> v = {1, 2, 3, 4, 5};
    int c = std::count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
    std::cout << c << '\n';
    return 0;
}

Cuándo usar un functor

Un functor (una estructura con operator()) es adecuado para una operación reutilizable y con nombre que pueda contener configuración y usarse en varios lugares.

#include <iostream>
#include <vector>
#include <algorithm>

struct AboveThreshold {
    int limit;
    bool operator()(int x) const { return x > limit; }
};

int main() {
    std::vector<int> v = {1, 5, 2, 8};
    std::cout << std::count_if(v.begin(), v.end(), AboveThreshold{4}) << '\n';
    return 0;
}

Lambda frente a bind

Ambos permiten rellenar previamente argumentos. La versión con lambda suele ser más clara y más fácil de optimizar para el compilador, así que prefiera una lambda a std::bind.

#include <iostream>

int power(int base, int exp) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    auto square = [](int x) { return power(x, 2); };
    std::cout << square(6) << '\n';
    return 0;
}

Cuándo usar std::function

Use std::function cuando deba almacenar un objeto invocable cuyo tipo concreto desconozca, por ejemplo, en un miembro de clase o un contenedor.

#include <iostream>
#include <functional>
#include <vector>

int main() {
    std::vector<std::function<int(int)>> pipeline;
    pipeline.push_back([](int x) { return x + 1; });
    pipeline.push_back([](int x) { return x * 3; });
    int v = 2;
    for (auto& f : pipeline) v = f(v);
    std::cout << v << '\n';
    return 0;
}

Las plantillas evitan sobrecostes

Si una función solo necesita recibir un objeto invocable, y no almacenarlo, un parámetro de plantilla mantiene todo el rendimiento al evitar el borrado de tipos.

#include <iostream>

template <typename F>
int applyTwice(int x, F f) { return f(f(x)); }

int main() {
    std::cout << applyTwice(3, [](int n) { return n + 10; }) << '\n';
    return 0;
}

Clasificación del rendimiento

A grandes rasgos: un objeto invocable basado en plantillas o una lambda sin captura son los más rápidos, un puntero a función se acerca bastante y std::function es el más lento debido a la indirección y a una posible reserva de memoria.

#include <iostream>
#include <functional>

int main() {
    auto fast = [](int x) { return x + 1; };
    std::function<int(int)> flexible = fast;
    std::cout << fast(1) << ' ' << flexible(1) << '\n';
    return 0;
}

Una guía para decidir

Guía rápida:

  • ¿Necesita almacenar cualquier objeto invocable? std::function.
  • ¿Solo necesita recibir uno en una función genérica? Un parámetro de plantilla.
  • ¿Necesita un comportamiento insertado directamente con estado? Una lambda.
  • ¿Necesita una API de C o un objeto sin estado? Un puntero a función.
#include <iostream>
#include <functional>

void runStored(const std::function<void()>& cb) { cb(); }

template <typename F>
void runGeneric(F f) { f(); }

int main() {
    runStored([] { std::cout << "stored\n"; });
    runGeneric([] { std::cout << "generic\n"; });
    return 0;
}

Unirlo todo

Un sistema de eventos pequeño podría recibir controladores de forma genérica, pero almacenarlos en std::function para poder invocarlos más tarde.

#include <iostream>
#include <functional>
#include <vector>

struct Dispatcher {
    std::vector<std::function<void(int)>> handlers;
    template <typename F> void on(F f) { handlers.emplace_back(f); }
    void fire(int e) { for (auto& h : handlers) h(e); }
};

int main() {
    Dispatcher d;
    d.on([](int e) { std::cout << "got " << e << '\n'; });
    d.fire(7);
    return 0;
}

Comprobación rápida

Compruebe cuánto entiende sobre la elección de objetos invocables.

Repaso

Aprendió a elegir un objeto invocable:

  • puntero a función para callbacks sin estado y compatibles con C
  • lambda como opción predeterminada para comportamientos insertados directamente y con estado
  • functor para operaciones reutilizables con nombre
  • parámetro de plantilla cuando solo recibe un objeto invocable, ya que ofrece el máximo rendimiento
  • std::function cuando debe almacenar uno cuyo tipo desconoce

Con esto completa el curso de Objetos función y std::bind.

Preguntas frecuentes

¿La lección «Elección de objetos invocables» es gratis?

Sí — el texto completo de «Elección de objetos invocables» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C++ Academy, actualiza a CoddyKit PRO. El curso de C++ Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Elección de objetos invocables»?

Lambdas frente a bind y punteros Practicas C++ Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C++ Academy?

No se requiere experiencia previa. C++ Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Elección de objetos invocables»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C++ Academy?

Sí. Cada lección de C++ Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Punteros a funciones
  2. std::function
  3. std::bind
  4. Elección de objetos invocables
← Volver a C++ Academy