无法从临时 std::array<int 构造 std::span<int>>

Can't construct std::span<int> from temporary std::array<int>

提问人:Jan Schultke 提问时间:6/23/2023 最后编辑:Jan Schultke 更新时间:9/13/2023 访问量:132

问:

我有以下代码,我希望它能工作,但它没有:

#include <array>
#include <span>

void foo(std::span<int>);

int main() {
    foo(std::array<int, 3>{});
}

clang 无法编译以下内容:

<source>:7:5: error: no matching function for call to 'foo'
    7 |     foo(std::array<int, 3>{});
      |     ^~~
<source>:4:6: note: candidate function not viable: no known conversion from 'std::array<int, 3>' to 'std::span<int>' for 1st argument
    4 | void foo(std::span<int>);
      |      ^   ~~~~~~~~~~~~~~

我希望这会调用构造函数:

template< class U, std::size_t N >
constexpr span( const std::array<U, N>& arr ) noexcept; // (6)

4-6) 构造一个跨度,该跨度是数组 arr 的视图;生成的跨度为 和 。size() == Ndata() == std::data(arr)

仅当 is 且从 to 的转换最多是限定转换时,这些重载才会参与重载解析。extent == std::dynamic_extent || N == extenttruestd::remove_pointer_t<decltype(data(arr))>element_type

请参阅 cppreference 上的 std::span::span

为什么不满足此构造函数的约束?

  • extent == std::dynamic_extent对于 ,因此显然满足了第一个要求std::span<int>
  • std::remove_pointer_t<decltype(data(arr))>是 ,等于 ,因此也满足第二个要求intstd::span<int>::element_type = int

我看不出有什么理由我不能调用这个构造函数。

C++ 初始化 C++20 stdarray std-span

评论

0赞 Jan Schultke 9/13/2023
@Barry编辑后的版本现在解决了这个问题,并且不会立即产生悬空的跨度。

答:

2赞 Artyer 6/23/2023 #1

资格转换只能使某些东西更合格。

decltype(data(arr))用于 . 无法通过资格转换进行转换。const int*const std::array<int, 3>&const intint

std::span<const int>(std::array<int, 3>{})但是确实有效 ( -> )。const intconst int

评论

0赞 Jan Schultke 6/23/2023
那么,从临时数组构造一个最简短的方法是什么,或者没有单行代码呢?std::span
0赞 Artyer 6/23/2023
@JanSchultke 是获取临时值的非常量值的好方法。所以,或者如果你想要那个班轮。但是,在一组非常特定的情况下,这没有用,因为阵列会立即死亡。为什么不直接使用(隐式转换为跨度)?auto& unmove(auto&& temporary) { return temporary; }std::span<int>(unmove(std::array<int, 3>{}))std::span<int>([](auto&& arr)->auto&{return arr;}(std::array<int, 3>{}))auto f = std::array<int, 3>{}
0赞 Jan Schultke 6/23/2023
它应该演示如何避免模板参数包,转而使用 、 、 等。std::spanstd::initializer_liststd::array
0赞 Artyer 6/23/2023
std::initializer_list也是 const,因此您可能正在寻找 const span。也许还有两个重载:void f(std::span<const int>); inline void f(std::initializer_list<int> ilist) { f(std::span{ilist}); }
0赞 Jan Schultke 6/23/2023
实际上,我一直在寻找相反的情况,因为我想从跨度中移动,而 a or not 真的让你这样做std::initializer_liststd::span<const>