In python, we can do this:
int_list = [1, 2, 3, 4, 5]
print(sum(int_list)) # prints 15
float_tuple = (1.2, 3.4, 9.9)
print(sum(float_tuple)) # prints 14.5
The sum
function takes any iterable of elements that know how to be added to each other and to 0 and produces the sum.
I wanted to make an identical function in C++11. I'm aware that there exists the accumulate
method, but I want a function that takes a single parameter. Essentially, I want to know how to make the following code compile:
#include <string>
#include <iostream>
#include <vector>
#include <deque>
#include <list>
template<typename iterable>
auto sum(iterable iterable_) {
auto it = iterable_.begin();
auto end = iterable_.end();
if (it == end) {
return 0;
}
auto res = *(it++);
while (it != end) {
res += *it++;
}
return res;
}
int main() {
std::vector<int> int_vector = {0, 1, 2, 3, 4, 5};
std::cout << sum(int_vector) << '\n'; // prints 15
std::deque<int> int_deque = {4, 5, 7};
std::cout << sum(int_deque) << '\n'; // prints 16
std::list<float> float_list = {1.2, 3.4, 9.9};
std::cout << sum(float_list) << '\n'; // should print 14.5, but produces error.
}
This code almost works. The issue is that auto
sees the return 0;
in the case that the iterable is empty and it assumes that the function must return an int
. Then it sees that the float
version returns a float
and it gets confused. Is there any way to tell the compiler to, say return float(0)
if it sees that the return
later on returns float
?
Yes, you can make this work at least for standard containers.
A standard container defines a type alias named value_type
for the type of value stored in that container. For an empty container, you can return a value-constructed object of this type:
template<typename iterable>
auto sum(iterable const &iterable_) {
auto it = iterable_.begin();
auto end = iterable_.end();
if (it == end) {
return typename iterable::value_type();
}
auto res = *(it++);
while (it != end) {
res += *it++;
}
return res;
}
This does depend on the contained type being default-constructible, but that's probably not a major problem (certainly works for primitive types like int
and float
).