Because you use 0 as the last parameter (the "initial value"), which is of type int; and this deduces T = int. (*)
I recommend to use foo.value_type() as the last parameter. This evaluates to zero for primitive types such as int, float, double, etc.
You can wrap this in a function template accumulate_zero to save some redundant work if needed often. The following function template implements this by setting T to the value type of the passed iterator:
template<class InputIt,
class BinaryOperation,
class T = typename std::iterator_traits<InputIt>::value_type>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
T accumulate_zero(InputIt first, InputIt last, BinaryOperation op)
{
return std::accumulate(first, last, T(), op);
// ^^^
}
(*) That's simply how type deduction works. std::accumulate is a function template with, among others, the type T being a template parameter. If not given explicitly and if possible, it is deduced from the passed argument's type.