看看这个例子:
#include <span>
#include <vector>
class Data
{
public:
Data() = default;
template<class R>
explicit Data(R& r)
: buf_(r)
, header_(buf_.first<4>())
{}
private:
std::span<char> buf_;
// compile error
// std::span<char, 4> header_;
// compiles but ill-formed (against the precondition of [span.sub])
std::span<char, 4> header_{buf_.first<4>()};
};
int main()
{
std::vector<char> buf(1234);
Data data{buf};
}
编译错误的原因是标准[span.cons]中明确禁止:constexpr span() noexcept;
Constraints:
Extent == dynamic_extent || Extent == 0
is true.
Postconditions:size() == 0 && data() == nullptr
.
为什么会存在这个约束?
由于
dynamic_extent
的跨度的默认构造已经允许,感觉这两种情况在语义上是相同的:std::span<char> header_; // allowed
std::span<char, 4> header_; // why disallowed?
此外,看看[span.obs]的措辞:constexpr size_type size() const noexcept;
Effects: Equivalent to:
return size_;
例如,标准甚至可以定义更严格的实现细节以鼓励静态优化。如果这个措辞类似于
Returns Extent when Extent != dynamic_extent
, size_
数据成员可以在运行时省略。如果是这样,我知道默认构造是无效的,因为在这种情况下 size()
将始终返回无效大小,即 Extent
,不为零。但是,当前标准在类定义中公开了非静态成员变量 [span.overview] :
private:
pointer data_; // exposition only
size_type size_; // exposition only
既然我们已经有了这些变量,标准库就不能设置data_ = nullptr
吗?和 size_ = 0
当静态大小的跨度是默认构造的?我当然可以接受当前的措辞,但是当前的标准是不是期望有太强的限制?请注意,委员会曾经尝试修复 LWG3198 中的 [span.cons]。 ,所以我很确定他们对当前的措辞有一些理由。
最佳答案
默认构建的 std::span<T>
成功引用了 T
类型的 0 个对象从 nullptr
开始.对什么 3 个对象类型 T
是否std::span<T,3>()
引用?size_
成员始终在场纯粹是一种简化规范的叙述手段;对于静态范围跨度,它没有任何意义,并且在实践中确实不存在。
关于c++ - 为什么在具有静态范围的 std::span 中不允许默认构造?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66809280/