std::vector 到 std::span<T> 的转换

Too*_*one 2 c++ c++20 ctad

我想将我的代码概括为采用std::span而不是std::vector作为参数,但不会失去传入 a 时获得的自动转换的便利性std::vector(请参阅如何将 std::vector 转换为 std::span?)。

然而,有问题的函数是在元素类型上模板化的——我在use_span_t下面得到了编译失败的信息。

void use_span(std::span<const double>) {}

template <typename T>
void use_span_t(std::span<const T>)
{
}

const std::vector<double> v{1, 2, 3};
use_span(v); // ok
use_span_t(v); // candidate template ignored: could not match 'span' against 'vector' (clang16)
use_span_t<double>(v); // ok
Run Code Online (Sandbox Code Playgroud)

我做错了什么,是否有一种解决方法,它不涉及调用站点(use_span_t<double>)的显式类型,或者在被调用站点上不涉及以下内容。

template <typename T>
void use_span_t(const std::vector<T>& v)
{
    use_span_t(v);
}

Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 5

这个函数模板基本没什么用:

template <typename T>
void use_span_t(std::span<const T>);
Run Code Online (Sandbox Code Playgroud)

因为它不仅不接受vector<double>orvector<double> const正如您所看到的,它甚至不接受span<double>. 准确地说,它接受一个span<double const>. 这是非常有限的。如果有一种方法可以实现这一点那就太好了,但是......

在那之前,如果您想要做的是推断T任何连续范围并获得跨度T const,则必须这样做:

template <typename T>
void f(std::span<const T>);

template <std::ranges::contiguous_range R>
    requires std::ranges::sized_range<R>
void f(R&& r) {
    f(std::span<const std::ranges::range_value_t<R>>(r));
}
Run Code Online (Sandbox Code Playgroud)

任何contiguous+sized都可以转换为span,我们只需明确地执行即可。range_value_t<R>为我们提供了值类型(适用doublevector<double>const vector<double>),因此我们可以使用它来构造正确的span

如果我们已经使用fa进行调用span<T const>,则会选择第一个重载。任何其他内容,包括span<T>(对于非const T),都会选择第二个,然后转发到第一个。

差不多两年前,我还写了一篇关于强制深度常量的文章。