7

I was testing some of the tools in the type_traits header over the new C++14 runtime sized arrays, consider the code below:

int g[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

template <typename T> void print(T &t)
{
    std::cout << "Type id:    " << typeid(T).name() << '\n';
    std::cout << "is_array:   " << std::is_array<decltype(T)>::value << '\n';
    std::cout << "is_pointer: " << std::is_pointer<decltype(T)>::value << '\n';
    std::cout << "extent:     " << std::extent<decltype(T)>::value << '\n';
}

int main()
{
    print(g);
    return 0;
}

The static sized array g returns the following output:

Type id:    A11_i
is_array:   1
is_pointer: 0
extent:     11

The unmangled name A11_i I'm assuming that is Array of 11 elements of type int so all is correct here, but with this new code:

void f(std::size_t s)
{
    int a[s];
    print(a);
}

int main()
{
    f(5);
    return 0;
}

I'm getting errors:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T&)
note:   template argument deduction/substitution failed:
note:   variable-sized array type 'int [s]' is not a valid template argument

I wasn't expecting that the size argument could be passed to the template but I was expecting an automatic array-to-pointer decay. I guess that the argument T & isn't suited for this kind of decay so I've tried to change the template signature to:

template <typename T> void print(T *&t)

With similar results:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T*&)
note:   template argument deduction/substitution failed:
note:   mismatched types 'T*' and 'int [s]'

And I've noticed that the size variable on the runtime sized array seems to be tied to the type (instead of mismatched types 'T*' and 'int [5]' we're getting mismatched types 'T*' and 'int [s]') this looks pretty weird.

So, what's the question?

  • Why I'm not getting an array-to-pointer decay in this runtime sized array?
  • Is the variable used to size the runtime sized array part of the type of the runtime sized array or I'm misunderstanding the error?
PaperBirdMaster
  • 12,806
  • 9
  • 48
  • 94
  • 1
    Note that you use VLA extension with `int a[s];` – Jarod42 Apr 13 '15 at 10:04
  • A lot of compiler flags or code norms forbid to use a runtime sized array. (I know G++ with warning flags forbid it for example) It is possible that your compiler refuses to use it as a template. – Aracthor Apr 13 '15 at 10:11
  • 5
    To expand on Jarod42's comment, runtime sized arrays were proposed but not eventually included in the final c++14 standard. – eerorika Apr 13 '15 at 10:15
  • My bad! I really thoguth that runtime sized arrays were included in C++14 (that's why I added the C++14 tag). Anyway it doesn't change the question: *why VLA doesn't decay to pointer in this example*? – PaperBirdMaster Apr 13 '15 at 10:18
  • Does it work with a precise-sized array ? Like if you test it with `a[5];` instead of `a[s];` ? – Aracthor Apr 13 '15 at 10:23
  • For decay to pointer you'd need the parameter type to be `T*`, not `T*&`. The latter would only work with actual pointers. – interjay Apr 13 '15 at 10:26
  • @interjay I've tested with `T*` and it decayed, so if you make an answer of the comment (explaining why `T*` decays while `T*&` does not) I'll accept the answer. – PaperBirdMaster Apr 13 '15 at 10:31
  • [dcl.init.ref]/p5: "The usual lvalue-to-rvalue (4.1), **array-to-pointer** (4.2), and function-to-pointer standard conversions are not needed, and therefore are suppressed, when such direct bindings to lvalues are done." Note that the pointer returned from the array-to-pointer conversion will be an rvalue, so it wouldn't work anyway if it occurred since you can't initialize a non-const lvalue-reference with an rvalue. – David G Apr 13 '15 at 13:21

1 Answers1

3

During template argument deduction, the array-to-pointer conversion is only used if the function template parameter's type is not a reference.

§14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]

1 Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. [...]

2 If P is not a reference type:

  • If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction; otherwise,
  • [...]
T.C.
  • 133,968
  • 17
  • 288
  • 421