5

The below code just works fine for me.

#include <iostream>
using namespace std;

template<class T>
T sum_array(T (&a)[10], int size)
{
    T result=0;
    for(int i=0; i<size; i++)
    {
        result = a[i] + result;
    }
    return result;
}

int main()
{
    int a[10] = {0,1,2,3,4,5,6,7,8,9};
    cout<<sum_array(a, 10)<<endl;
    double d[10] = {1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1};
    cout<<sum_array(d, 10)<<endl;
    cin.get();
}

But if try to make my function more generic by removing the array size as shown below in function it gives a error saying no instance of function template.

template<class T>
T sum_array(T (&a)[], int size)
{
    T result=0;
    for(int i=0; i<size; i++)
    {
        result = a[i] + result;
    }
    return result;
}

At the same time if i remove the reference as shown below it just works fine.

template<class T>
T sum_array(T a[], int size)
{
    T result=0;
    for(int i=0; i<size; i++)
    {
        result = a[i] + result;
    }
    return result;
}

I am relatively new to templates can you please explain the above behavior.

Naveen
  • 53
  • 1
  • 4

2 Answers2

9

In funciton parameters, [] (without a dimension inside) is just alternate syntax for a pointer, as arrays decay to pointers when passed into functions, unless they're passed by reference.

This means that your working generalised template (the one with T a[]), is exactly the same as T a*. If you're passing the size in at runtime anyway, all is fine and you can just use that (and it will work for other things not declared as arrays, such as the return value of std::string::c_str()).

However, if you want to generalise the tempalte but still keep it limited to actual arrays, you can do this:

template<class T, size_t N>
T sum_array(T (&a)[N], int size)
{
    T result=0;
    for(int i=0; i<size; i++)
    {
        result = a[i] + result;
    }
    return result;
}

That way, only a genuine array can be passed in, but both its type T and its length N will be deduced. Depending on your use case, you might get away with removing the size parameter in such case.

Angew is no longer proud of SO
  • 161,995
  • 14
  • 331
  • 433
  • You can change it to template T sum_array(T (&a)[N]). Readers might not read your last line. – ashish Feb 07 '18 at 06:07
1

If you want to bind an array by reference, you will absolutely need to know the array's size. You can have the compiler deduce the size, however. Assuming the logic in your code is non-trivial, it is a good idea to immediately delegate to version which is independent of the array's size. Here is an example:

template<typename T>
T sum_array(T const* a, int size)
{
    return std::accumulate(a, a + size, T());
}

template <typename T, int Size>
T sum_array(T const (&array)[Size]) {
    return sum_array(array, Size);
}

Of course, I couldn't resist to also use std::accumulate() from <numeric>: if there is an algorithm for this, it is a good idea to use it.

Since you wondered about removing the reference from the array: when using T[] for the type of a function parameter, it is equivalent to using T*. Even if you'd use T[10] for the type of a function parameter, the compiler would read it as T*.

Dietmar Kühl
  • 145,940
  • 13
  • 211
  • 371