9

This question is about functions that take arrays of statically known size.

Take for example the following minimal program:

#include <iostream>

template<size_t N>
void arrfun_a(int a[N])
{
    for(size_t i = 0; i < N; ++i)
        std::cout << a[i]++ << " ";
}

int main()
{
    int a[] = { 1, 2, 3, 4, 5 };
    arrfun_a<5>(a);
    std::cout << std::endl;
    arrfun_a<5>(a);

    return 0;
}

Which, when run, prints the expected result:

2 3 4 5 6
3 4 5 6 7

However, when I tried to have my compiler (VS 2010) deduce the 5, it could not deduce template argument for 'int [n]' from 'int [5]'.

A bit of research resulted in the updated arrfun_b where the template parameter deduction works:

template<size_t n>
void arrfun_b(int (&a)[n])
{
    for(size_t i = 0; i < n; ++i)
        std::cout << ++(a[i]) << std::endl;
}

The result of the program is the same, whether arrfun_a or arrfun_b is called.

So far, the only difference I have found is whether the template argument deduction works and if it is possible to call the function with an N that is not 5...

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
danielschemmel
  • 10,885
  • 1
  • 36
  • 58
  • 2
    Are you sure, that 'both versions allow explicitly passing an N that is smaller or larger'? It shouldn't and [doesn't](http://ideone.com/74FaV) for me. And it is another _pro_ to use reference version – Lol4t0 May 08 '12 at 19:46
  • Thank you for fixing my confusion! At some place during the testing, I must have screwed up with that! – danielschemmel May 08 '12 at 19:52
  • You must didn't delete non-reference version and created an overload, that was called. – Lol4t0 May 08 '12 at 19:53
  • Related: http://stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-an-array (not really a dupe) – Flexo May 08 '12 at 19:55

2 Answers2

15

The compiler silently changes the type of function argument int a[N] to int *a and thus loses the size of the array. int(&a)[5] is truly a reference to an array of size 5, and cannot be passed an array of any other size.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 5
    More importantly, `int a[5]` becomes `int *a` in a parameter list where `int (&a)[5]` is truly a **reference** to an array of 5 `int`s – D.Shawley May 08 '12 at 19:39
  • 1
    @D.Shawley, I implied that but didn't make it explicit. Thanks. – Mark Ransom May 08 '12 at 19:40
  • In that case, the call to `arrfun_a` would include an array-to-pointer decay followed by an implicit pointer-to-array-of-five conversion, leaving me with a totally useless compiler message? *great* – danielschemmel May 08 '12 at 19:46
  • 3
    @dionadar: There is no conversion back to an array. Inside arrfun_a, the type of `a` is a pointer. – Benjamin Lindley May 08 '12 at 19:51
  • 1
    OK, that finally got me what I was looking for: "[...] After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively. [...]" (8.3.5.5 in the C++ 11 standard) – danielschemmel May 08 '12 at 20:13
  • Call me an old C fogey, but I don't see any "conversion" from int a[N]. int a[] IS int* a. a[i] is just shorthand for *(a+i) where a is pointer to int and i is an int offet. – Julian May 08 '12 at 20:30
  • @Julian, you're confusing declarations with array indexing. Although they use the same syntax they are two different things. – Mark Ransom May 08 '12 at 20:36
  • @Julian `a[i]` is the same as `*(a+i)` because if `a` is an array then `a[i]` causes it to decay. _The array index operator does not operate on arrays._ But this doesn't mean that `int a[]` is nothing more than shorthand for `int *a`. The issue is simply that C arrays [behave](http://stackoverflow.com/a/10264383/365496) [bizarrely](http://stackoverflow.com/a/10253277/365496). – bames53 May 08 '12 at 21:05
  • @bames53 - in K&R C int a[] was definately just shorthand for pointer arithmetic - they borrowed it from BCPL. I'm sure you are right about how its defined now. – Julian May 08 '12 at 22:09
1

I think its the difference between a reference and a pointer.

arrfun_a passes a pointer to int.

arrfun_b passes a reference to an array of ints.

Julian
  • 1,522
  • 11
  • 26