繁体   English   中英

是`std :: array <T, 0> `默认可构造的,而`T`不是默认可构造的?

[英]Is `std::array<T, 0>` default constructible where `T` is not default constructible?

考虑下面的代码:

#include <array>

struct T
{
    T() = delete;
};

int main()
{
    std::array<T, 0> a;
    a.size();
}

我们默认初始化一个0大小的数组。 由于没有元素,因此不应调用T构造函数。

但是, Clang仍然要求T是默认可构造的,而GCC接受上面的代码。

请注意,如果我们将数组初始化更改为:

std::array<T, 0> a{};

Clang这次接受了。

非默认可构造的T是否会阻止std::array<T, 0>成为默认可构造的?

由于没有元素,因此不应调用T的构造函数。
非默认可构造的T是否会阻止std::array<T, 0>成为默认可构造的?

该标准没有指定std::array<T, 0>应该具有什么布局才能让我们回答。 零大小数组专门化仅表现如下:

[array.zero]

1个数组应为特殊情况N == 0提供支持。
2在N == 0的情况下,begin()== end()==唯一值。 data()的返回值未指定。
3为零大小的数组调用front()或back()的效果是不确定的。
4成员函数swap()应具有非抛出异常规范。

您注意到的行为很可能仅是由于实现上的差异。

感谢@TC,正如他在评论中所指出的那样,该问题已在LWG 2157中得到解决,在撰写本文时仍是一个未解决的问题。

拟议的决议增加了这一要点(强调我的意思):

对于这种情况,未指定的数组内部结构应允许初始化,例如:

 array<T, 0> a = { }; 

并且即使T是不可缺省构造的 ,所述初始化也必须有效。

因此很明显,预期的行为是使std::array<T, 0>默认可构造,即使T不是。

这个问题解释了clang和std::array 删除默认构造函数会发生什么 仍然可以创建对象...有时

但是与gcc的区别来自库代码。 确实在gcc代码库中有一个与该问题相关的具体实现细节,如@StoryTeller所述

gcc对于大小为0的std::array有特殊情况,请参见其<array>头中的以下代码(来自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; }
};

如您所见,当数组大小为0时, __array_traits被特殊化(用于基础数组的std::array中),甚至没有其模板化类型的数组。 _Type类型不是数组,而是空结构!

这就是为什么没有调用构造函数的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM