cbhattac
cbhattac

Reputation: 273

Why does C++ span's C style array constructor need type_identity_t?

The C style array constructor for span is specified as follows

template<size_t N> constexpr span(
   type_identity_t<element_type> (&arr)[N]) noexcept;

Why is type_identity_t necessary? instead of just:

template<size_t N> constexpr span(
   element_type (&arr)[N]) noexcept;

As was originally defined in this proposal?

Upvotes: 4

Views: 233

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275820

As cbhattac's answer explains, the problem was that span's deduction guide's picked the wrong overload.

In issue3369 a fix was developed.

The core problem was that:

template <size_t Size>
  requires (Extent == dynamic_extent || Extent == Size)
span(T (&)[Size]) {}

ctor generates an implicit deduction guide, and so does

template <typename T, size_t Extent>
span(T (&)[Extent]) -> span<T, Extent>;

The constructor builds a span with variable length, and the deduction guide builds one with a fixed length.

When passed an array of fixed length, the ideal deduced span should also be of fixed length. But it wasn't happening.

Naively, explicit deduction guilds beat ones produced from constructors, but that isn't true -- the constructor here is more constrained due to the requires (Extent == dynamic_extent || Extent == Size) clause. So it beats the deduction guide.

To fix this, type_identity_t<T> was used to block CTAD with this constructor completely. (An alternative that would also work was to add a trivial constraint to the deduction guide).

Upvotes: 1

cbhattac
cbhattac

Reputation: 273

It was because "span's deduction-guide for built-in arrays did not work" without that change. Please check this link for more details.

Upvotes: 0

Related Questions