Last updated:2026-10-12
Ways to Return Multiple Values in C++¶
Today let me pose another fairly classic interview question: how can a function return multiple results? How many ways can you think of?
In fact, this question tests a great deal of knowledge, covering:
- pointers
- references
- lambda
- functional
- tie
- tuple
- struct binding
- template deduction
- and so on
This article will answer the question using different methods. First, let's transform the problem: use a / b to simulate it (below, the case where the divisor is 0 is not considered) and return the quotient and the remainder. Simply put, the question becomes: in how many ways can a function return the quotient and the remainder?
Now let's get to the point. Note: all the code in this section was first published in the Knowledge Planet; if you are interested, scan the QR code below.
1. Pointers and References¶
Change the interface by adding two parameters, using pointers and references.
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;
}
The drawback of this approach is plain to see: once there are more than two return values, the interface becomes very long. Moreover, if the interviewer requires you not to change the function interface, this method is unusable.
2. Tuple + Tie¶
The combination of tuple and tie provides a concise way for a function to return multiple values. By using std::tie, we can unpack the elements of the tuple into different variables, improving the clarity of the code.
This method counts as one of the standard answers; it is fairly simple and clear, and a pair also works if the return values are two.
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¶
Transforming the above, structured bindings introduced in C++17 further simplify code that returns multiple values. Using auto with structured bindings makes the code more intuitive and easier to understand.
If the interviewer asks you to further refine the method above, it can become the code example below, which uses structured bindings to make the code more elegant.
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. Function Callbacks¶
In everyday projects, especially open-source projects, a callback is a commonly used technique: by passing a callback that handles the return values, users customize the processing, which realizes returning multiple values and yields a more flexible code structure. This is very useful for scenarios such as asynchronous programming and event handling.
void divide(int dividend, int divisor, std::function<void(int, int)> callback) {
callback(dividend / divisor, dividend % divisor);
}
5. Custom Out¶
A custom out is a way of wrapping things in a struct, making the output parameters members of the struct. This approach improves the readability of the code and is especially suitable for functions that need to return multiple values.
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. Template Deduction¶
C++ template deduction provides developers with a more flexible and concise way of writing code. With template deduction, we can handle data of different types without explicitly specifying the types.
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);
All in all, C++ provides many ways to achieve multiple return values, and each has its applicable scenarios. Choosing the right one depends on the specific requirements; developers can use these features flexibly according to code structure and readability.
Related Topics¶
- C++ Pure Virtual Functions and Abstract Classes | C++那些事
- C++ assert | C++那些事
- C++ Bit Fields | C++那些事
- Implementing C++ Polymorphism in C | C++那些事
- C++ const Constants and Qualifiers | C++那些事
- The Complete C++ const Family | C++那些事
- C++ Dereference Operator * | C++那些事
- C++ Initialization and Assignment | C++那些事
- C++ mutable Keyword | C++那些事
- C++ restrict and Compiler Optimization | C++那些事