Ú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;
}
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);
Temas relacionados¶
- Funciones virtuales puras y clases abstractas en C++ | C++那些事
- Aserciones assert en C++ | C++那些事
- Campos de bits en C++ | C++那些事
- Implementar el polimorfismo de C++ en lenguaje C | C++那些事
- const en C++: constantes y modificación | C++那些事
- La familia completa de const en C++ | C++那些事
- El operador de desreferencia * en C++ | C++那些事
- Inicialización y asignación en C++ | C++那些事
- La palabra clave mutable en C++ | C++那些事
- C++ restrict y optimización del compilador | C++那些事