Is `std::array` default constructible where `T` is not default constructible?

后端 未结 3 1816
谎友^
谎友^ 2021-01-08 00:18

Consider the code below:

#include 

struct T
{
    T() = delete;
};

int main()
{
    std::array a;
    a.size();
}
<
相关标签:
3条回答
  • 2021-01-08 00:26

    Thanks to @T.C., as pointed out in his comment, it's addressed in LWG 2157, which is still an open issue as of this writing.

    The proposed resolution adds this bullet point (emphasis mine):

    The unspecified internal structure of array for this case shall allow initializations like:

    array<T, 0> a = { };
    

    and said initializations must be valid even when T is not default-constructible.

    So it's clear that the intended behavior is to have std::array<T, 0> default constructible even when T is not.

    0 讨论(0)
  • 2021-01-08 00:32

    Since there's no elements, no constructor of T should be called.
    Does non-default-constructible T prevent std::array<T, 0> from being default-constructible?

    The standard doesn't specify what layout std::array<T, 0> should have for us to answer that. The zero sized array specialization is only said to behave as follows:

    [array.zero]

    1 array shall provide support for the special case N == 0.
    2 In the case that N == 0, begin() == end() == unique value. The return value of data() is unspecified.
    3 The effect of calling front() or back() for a zero-sized array is undefined.
    4 Member function swap() shall have a non-throwing exception specification.

    The behavior you note is most probably due to differences in implementation alone.

    0 讨论(0)
  • 2021-01-08 00:43

    This question explains what happens with clang and std::array Deleted default constructor. Objects can still be created... sometimes

    But with gcc the difference comes from the library code. There is indeed a specific implementation detail in the gcc codebase that is relevant to this question as @StoryTeller mentioned

    gcc has a special case for std::array with a size of 0, see the following code from their <array> header (from gcc 5.4.0)

    template<typename _Tp, std::size_t _Nm>
    struct __array_traits
    {
      typedef _Tp _Type[_Nm];
    
      static constexpr _Tp&
      _S_ref(const _Type& __t, std::size_t __n) noexcept
      { return const_cast<_Tp&>(__t[__n]); }
    
      static constexpr _Tp*
      _S_ptr(const _Type& __t) noexcept
      { return const_cast<_Tp*>(__t); }
    };
    
    template<typename _Tp>
    struct __array_traits<_Tp, 0>
    {
     struct _Type { };
    
     static constexpr _Tp&
     _S_ref(const _Type&, std::size_t) noexcept
     { return *static_cast<_Tp*>(nullptr); }
    
     static constexpr _Tp*
     _S_ptr(const _Type&) noexcept
     { return nullptr; }
    };
    

    as you can see, there is a specialization of __array_traits (which is used in std::array for the underlying array) when the array size is 0, that doesn't even have an array of the type it's templated on. The type _Type is not an array, but an empty struct!

    That is why there are no constructors invoked.

    0 讨论(0)
提交回复
热议问题