8

What does it mean to have std::array<int,0>,array of size zero?

I have gone through similar questions in SO before posting this, and all those questions are regarding simple array type and for C language and most of them says that it is illegal. But in C++ array<int,0> is allowed.

As per cppreference.com

There is a special case for a zero-length array (N == 0). In that case, array.begin() == array.end(), which is some unique value. The effect of calling front() or back() on a zero-sized array is undefined.

Why isn't it defined as illegal?

David G
  • 94,763
  • 41
  • 167
  • 253
Sreeraj Chundayil
  • 5,548
  • 3
  • 29
  • 68

2 Answers2

11

What does it mean to have std::array,array of size zero?

The same as for example an empty std::vector or an empty std::set.

Why isn't it defined as illegal?

It is desirable to make it legal because it means generic programming does not have to handle a special case when the std::array's size is the result of a compile-time calculation.

It is possible to define it as legal thanks to template specialisation. For example, the implementation that comes with Visual C++ specialises std::array in a fashion similar to the following:

template<class T>
class array<T, 0> // specialisation
{
    // ...

    size_type size() const
    {
        return 0;
    }

    T elements[1]; // the raw array cannot have a size of 0
};

I suppose every compiler implements std::array like that.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • 1
    template specialization like that? What needless duplication, we have the conditional operator for that. – Deduplicator Mar 08 '15 at 17:13
  • 4
    That's a rather surprising implementation. Default constructing a `T` when I ask for an array of zero `T` is...odd. – T.C. Mar 08 '15 at 17:13
  • 1
    Hmm, libc++ does the same thing. libstdc++ doesn't, but then arguably invokes UB in their handling of `begin()` etc. for zero-sized arrays. – T.C. Mar 08 '15 at 17:17
  • @T.C: `begin()` is undefined behaviour for zero-sized `std::array`s, anyway. – Christian Hackl Mar 08 '15 at 17:18
  • Whoops, it's not, of course. I meant `front`. Sorry for the confusion. – Christian Hackl Mar 08 '15 at 17:18
  • @Deduplicator: `boost::array` apparently also does this via template specialisation (at least in 1.57.0), although it does not have a raw array member variable. – Christian Hackl Mar 08 '15 at 17:20
  • @Deduplicator: Strange enough, the VC header does *also* use the conditional operator in the non-specialised template: `_Ty _Elems[_Size == 0 ? 1 : _Size];`. I wonder why, though. In presence of the specialisation for 0, `_Size` can never be 0 there. – Christian Hackl Mar 08 '15 at 17:32
  • Summarizing http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2157: It is legal, but default-construction of `std::array` must be possible for all `T`. The wording should be less subtle though. – Deduplicator Mar 08 '15 at 17:59
  • This means you definitely can't use `std::array`, right? And are there no wacky overlaps between `std::array` and `std::array`, etc.? In any case it seems to me like the logic breaks down even if `std::array` is supported. If you have a "nople" of anything, IMO you should not have to worry if your nothing is constructible, or how big your nothing is before you have anything, etc. – John P May 08 '22 at 16:34
  • In libstdc++, `std::array` uses an empty struct (whose sizeof is 1) as its internal storage. There is no `T` constructed. – Steve Ward Aug 12 '22 at 22:07
2

std::array is considered like other standard containers that can be empty. So the specialization of the std::array with N equal to zero defines an empty container.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • But it's a little surprising because `std::array` encapsulates a C-style array, which is forbidden from having a size of zero. – Steve Ward Aug 12 '22 at 22:09