Saltar a contenido

Última actualización:2026-10-12

Formas de devolver varios valores en C++

Hoy planteamos otra pregunta de entrevista bastante clásica: ¿cómo puede una función devolver varios resultados? ¿Cuántas formas se te ocurren?

En realidad, esta pregunta evalúa muchísimos puntos de conocimiento, entre ellos:

  • Punteros
  • Referencias
  • lambda
  • functional
  • tie
  • tuple
  • struct binding
  • deducción de plantillas
  • etcétera

En este artículo responderemos a esta pregunta con distintos métodos. Primero transformamos el enunciado: usamos a / b para simularlo (abajo no se considera el caso de divisor 0), devolviendo el cociente y el resto. Dicho de forma simple: ¿de cuántas maneras puede una función devolver el cociente y el resto?

Entramos en materia. Nota: todo el código de esta sección se ha publicado primero en el planeta de conocimiento; si te interesa, escanea el código QR de abajo.

1. Punteros y referencias

Se modifica la interfaz añadiendo dos variables, usando punteros y referencias.

void divideWithReferences(int dividend, int divisor, int& quotient, int& remainder) {
  quotient = dividend / divisor;
  remainder = dividend % divisor;
}

void divideWithPointers(int dividend, int divisor, int* quotient, int* remainder) {
  if (quotient) *quotient = dividend / divisor;
  if (remainder) *remainder = dividend % divisor;
}
El inconveniente de este enfoque es evidente: cuando hay más de dos valores de retorno, la interfaz se vuelve muy larga. Además, si el entrevistador te pide no modificar la interfaz de la función, este método ya no sirve.

2. Tuple + Tie

La combinación de tuple y tie ofrece una forma concisa de que una función devuelva varios valores. Usando std::tie podemos desempaquetar los elementos del tuple en variables distintas, lo que mejora la claridad del código.

Este método puede considerarse una de las respuestas estándar; es bastante simple y claro, y si los valores devueltos son dos, también puede servir un pair.

std::tuple<int, int> divide(int dividend, int divisor) {
    return std::make_tuple(dividend / divisor, dividend % divisor);
}


std::tie(quotient, remainder) = divide(14, 3);
std::cout << quotient << ", " << remainder << std::endl;

3. Struct Binding

Rework del método anterior: los enlaces estructurados (structured bindings) introducidos en C++17 simplifican aún más el código de devolución múltiple. Usar auto y enlaces estructurados hace el código más intuitivo y fácil de entender.

Si el entrevistador te pide mejorar aún más el método anterior, puede convertirse en el siguiente ejemplo de código, usando enlaces estructurados para que el código sea más elegante.

auto divide(int dividend, int divisor) {
  struct result {
    int quotient;
    int remainder;
  };
  return result{dividend / divisor, dividend % divisor};
}
auto [quotient, remainder] = divide(14, 3);

4. Callback de función

En los proyectos cotidianos, especialmente en algunos proyectos de código abierto, el callback es una técnica habitual: pasando un callback que procesa los valores devueltos, se deja que cada usuario los trate a su manera, con lo que se logra devolver varios valores y una estructura de código más flexible. Esto es muy útil en escenarios como la programación asíncrona y la gestión de eventos.

void divide(int dividend, int divisor, std::function<void(int, int)> callback) {
  callback(dividend / divisor, dividend % divisor);
}

5. Out personalizado

El out personalizado es una forma de envolver mediante una estructura, tomando los parámetros de salida como miembros de la estructura. Este enfoque mejora la legibilidad del código y es especialmente adecuado para funciones que necesitan devolver varios valores.

template <class T>
struct out {
  std::function<void(T)> target;

  out(T* t)
      : target([t](T&& in) {
          if (t) *t = std::move(in);
        }) {}

  template <class... Args>
  void emplace(Args&&... args) {
    target(T(std::forward<Args>(args)...));
  }

  template <class X>
  void operator=(X&& x) {
    emplace(std::forward<X>(x));
  }

  template <class... Args>
  void operator()(Args&&... args) {
    emplace(std::forward<Args>(args)...);
  }
};

void divide(int dividend, int divisor, out<int>& quotient_out, out<int>& remainder_out) {
  quotient_out.emplace(dividend / divisor);
  remainder_out.emplace(dividend % divisor);
}

6. Deducción de plantillas

La deducción de plantillas de C++ ofrece una forma de escribir código más flexible y concisa. Mediante la deducción de plantillas podemos tratar datos de distintos tipos sin especificar los tipos explícitamente.

template <typename T1, typename T2>
struct many {
  T1 quotient;
  T2 remainder;
};

template <class T1, class T2>
many(T1, T2) -> many<T1, T2>;

many<int, int> divide(int dividend, int divisor) {
  return many{
      dividend / divisor,
      dividend % divisor,
  };
}

auto [quotient, remainder] = divide(14, 3);
En conjunto, C++ ofrece diversas formas de implementar la devolución de múltiples valores, y cada una tiene sus escenarios de aplicación. Elegir la adecuada depende de las necesidades concretas; según la estructura del código y la legibilidad, estas características pueden usarse con flexibilidad.

Temas relacionados

Comentarios