请看下面的代码。
#include <array>
#include <span>
std::array<int, 2> Foo()
{
return {1, 2};
}
int main()
{
std::array a = {3, 4};
std::span s1 = a;
// std::span s2 = Foo(); // Nope
// std::span s3 = std::move(a); // Nope
// std::span s4 = std::array<int, 2>{5, 6}; // Nope
// MSVC 19.29: 'initializing': cannot convert from 'std::array<int,2>' to 'std::span<int,18446744073709551615>'
// GCC 12.0.0: conversion from 'std::array<int, 2>' to non-scalar type 'std::span<int, 18446744073709551615>' requested
// clang 13.0.0: actually compiles!
}
似乎在clang中,只有当
std::array
是右值时才能将其转换为std::span
。我不确定这是否是问题的根源,但以下是
std::span
的构造函数与std::array
相关的MSVC实现。 template <class _OtherTy, size_t _Size>
requires (_Extent == dynamic_extent || _Extent == _Size)
&& is_convertible_v<_OtherTy (*)[], element_type (*)[]>
constexpr span(array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {}
template <class _OtherTy, size_t _Size>
requires (_Extent == dynamic_extent || _Extent == _Size)
&& is_convertible_v<const _OtherTy (*)[], element_type (*)[]>
constexpr span(const array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {}
乍一看,我没有发现任何问题。rvalue 应该与 const lvalue 引用绑定。
我的问题是:这段代码是否应该编译(如果是旧编译器的问题)或者不编译(如果是新编译器的问题)?
std::span
将指向已被清理的内存。你认为以下代码是有效的吗:std::string_view sv{ std::string{ "Hello there" } }
?像std::string_view
一样,std::span
不会拥有该对象。 - WBuckspan<int const, 2> s2 = Foo();
(这会让你陷入更多麻烦)。无论如何,我必须说:“span”是多么可怕、语义模糊的名称和设计! - alfC-stdlib=libc++
标志。https://godbolt.org/z/b3YnEvx3j - 康桓瑋void print(std::span<const int>)
。 - Jarod42