【发布时间】:2021-10-10 00:38:33
【问题描述】:
考虑下面的代码。
#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!
}
std::array 似乎可以转换为 std::span,而它仅是 clang 的右值。
我不确定这是否是问题的根源,但这里是 MSVC 对 std::array 相关构造函数的 std::span 的实现。
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) {}
乍一看,我看不出有什么问题。右值应绑定到 const 左值引用。
我的问题是:这段代码是否应该编译(这是前编译器的问题)还是不编译(这是后编译器的问题)?
【问题讨论】:
-
这是一个更大问题的简化案例,为了清楚起见,我不在这里展示,因此它可能看起来像一个糟糕的用例,我明白这一点。
-
有时简化版会过多地改变问题的性质,您可能会得到无法使用的答案。
-
@user4581301 谢谢,但在这种情况下它不会因为我只对代码是否应该编译感兴趣。
-
不编译是件好事。如果允许,
std::span将指向已清理的内存。您认为此代码有效吗:std::string_view sv{ std::string{ "Hello there" } }?。像std::string_view这样的std::span不获取对象的所有权。 -
有效(我的意思是没有生命周期问题)示例用法为
void print(std::span<const int>)。