c++c++14perfect-forwardinguniversal-referenceforwarding-reference

Equivalent static_asserts giving conflicting results for is_array<>


In the following snippet, an static assert passes and the other one fails:

template <class Rng> constexpr bool is_array(Rng&& r) {
  // int*** debug = r;  // uncomment this to debug r's type
  return std::is_array<Rng>{};
  // return std::is_array<decltype(r)>{};  // fails too
}

int a[5] = {0, 1, 2, 3, 4};
static_assert(std::is_array<decltype(a)>{}, ""); // passes
static_assert(is_array(a), ""); // fails

Tip: Remove the comment to debug the type (it is correctly deduced to be int [5]).

Why is this? Tested on clang trunk.

I'd guess it has something to do with arrays decaying into pointers.. somehow.

Solution: use std::remove_reference_t, Rng will be int (&)[5], this is a reference to an array, and not an array.

Xeo added:

template<class> struct dump;
dump<decltype(r)>{};

will fail to compile and reveal the correct type of r.

The int**** j = r; produced a wrong error (saying can't assing int[5] to int****).


Solution

  • The type of Rng is int (&)[5] which is a reference to an array (and not an array) and hence std::is_array returns false_type.

    One can remove the reference (e.g. using std::remove_reference_t) to make it work as you expected.