1

I have come across the following stripped down code that passes an array into a constructor:

struct FF
{
    template <int N> FF(int(&a)[N]);
private:
    void* arena_;
};


template <int N>
inline FF::FF(int(&a)[N])
    : arena_(a)
{
    /*empty*/
}

This can be called as follows:

int intArr[5];
FF ff(intArr);

Now, in int(&a)[N], clearly the template argument N is going to be taken from the size of the array, 5 in this case, but I don't understand the int(&a) part. Whenever I have passed an array before, I have always passed it to a function expecting a pointer (since passing an array is the same as passing the address of the first element of that array, so we effectively assign &array to *). But here we seem to be passing the address of the array to a constructor expecting what looks like a reference?

I then added a second constructor:

FF(int* pArr) {}

Now, the templated constructor doesn't get called at all, this one does!

Can someone please explain this strange templated form of the constructor and what it is saying, and then why when I add a constructor taking a pointer, the templated version doesn't get called at all?

Wad
  • 1,454
  • 1
  • 16
  • 33
  • 4
    "`int(&a)[N]`" declares `a` as "lvalue reference to array of `N` `int`". Blame C. – T.C. Mar 17 '17 at 19:47
  • OK, so how come it works when we pass the address of the array; doesn't `FF ff(intArr);` pass an address to a function expecting a reference? That can't work, because I can't say `int i; int& i2 = &i;`... – Wad Mar 17 '17 at 19:51
  • 1
    Arrays are not pointers. They *decay* to pointers at the drop of a hat, but until that hat drops they are still arrays. – T.C. Mar 17 '17 at 19:53
  • OK, so when I pass the name of an array to a function expecting a pointer, it _decays_ to a pointer. When I pass the name of an array to a function, or in this case, my constructor, expecting a reference, it doesn't decay. Correct? – Wad Mar 17 '17 at 19:55
  • 1
    @Wad, that is correct. – R Sahu Mar 17 '17 at 19:56
  • 1
    Right. So that just leaves the question as to why my version taking the pointer is preferred over the templated version. Can someone please post an answer to that, along with the information already given that explains the "odd" syntax? – Wad Mar 17 '17 at 19:58
  • 1
    related: http://stackoverflow.com/questions/21972652/array-decay-to-pointer-and-overload-resolution – A.S.H Mar 17 '17 at 20:19
  • 1
    It seems that in overload resolution, parameter as array reference or as pointer are considered a tie. Hence the non-template version wins. – A.S.H Mar 17 '17 at 20:22
  • Read here about [Best Viable Function](http://en.cppreference.com/w/cpp/language/overload_resolution#550) for more details about overload resolution. – A.S.H Mar 17 '17 at 20:28
  • Hmm, ok one more question: if `a` is being treated as a reference, how come I can assign it to a `void*` without taking the address of it? I changed the code in the constructor to be `arena_(&a)` and that also compiled, which is bizarre because there is a difference between `a` and `&a`! Can someone explain this please? – Wad Mar 17 '17 at 20:55
  • Nothing strange, you convert from `int*` to `void*` which is perfectly legal. `&a` is of type `int*` even if `a` is of type reference to int (`int&`). – A.S.H Mar 17 '17 at 21:04
  • Thanks, I get that, but how come I can assign both `a` **and** `&a` to `arena_` when one is a reference and the other is a pointer! Surely I should only be able to assign a pointer to a pointer! – Wad Mar 17 '17 at 21:07
  • 1
    @wad mods will complain about a long discussion :). Well since a is an array, it *is* a pointer, and any reference to it is also a pointer. Well, a reference to a pointer. – A.S.H Mar 17 '17 at 21:35

0 Answers0