c++c++11language-lawyerstdarray

Why is std::array< T, 0 > not empty?


Given any std::array< T, 0 >, why is it not empty? I mean "empty" as in:

std::is_empty< std::array< int, 0 > >::value

... returning false, and

#include <iostream>
#include <tuple>
#include <array>

struct Empty {};

int main()
{
    std::cout << sizeof(std::tuple<int>) << std::endl;
    std::cout << sizeof(std::tuple<int,Empty>) << std::endl;
    std::cout << sizeof(std::tuple<int,std::array<int,0>>) << std::endl;
}

yields

4
4
8

This means that for std::array<int,0>, the empty base optimization (EBO) is not applied.

This seem especially strange to me given that std::tuple<> (note: no template parameters) is empty, i.e., std::is_empty<std::tuple<>>::value does yield true.

Question: Why is that, given that size 0 is already a special case for std::array? Is it intentional or an oversight in the standard?


Solution

  • The standard doesn't say anything about whether tuple or array should be empty, what you're seeing are implementation details, but there's no reason to make tuple<> non-empty, whereas there is a good reason for array<T, 0> being non-empty, consider:

    std::array<int, sizeof...(values)> = { { values... } };
    

    When the parameter pack is empty you'd get:

    std::array<int, 0> = { { } };
    

    For the initializer to be valid the object needs a member, which cannot be int[0] because you can't have zero-sized arrays as members, so a possible implementation is int[1]

    An implementation doesn't have to special case the whole array, it can just do:

    T m_data[N == 0 ? 1 : N];
    

    and all other members work exactly the same way (assuming end() is defined as begin()+N)