为什么“std::span”需要在模板化函数中使用显式构造函数?[复制]

Why does `std::span` require an explicit constructor to use in a templated function? [duplicate]

提问人:SRSR333 提问时间:9/13/2023 更新时间:9/13/2023 访问量:70

问:

Godbolt 链接

我有以下功能:

#include <algorithm>
#include <iostream>
#include <numeric>
#include <ranges>
#include <span>
#include <type_traits>

template <typename T>
concept arithmetic = std::is_arithmetic_v<T>;

template <arithmetic T, std::size_t N>
auto sum(std::span<T, N> const a, 
         std::span<T, N> const b, 
         std::span<T, N> const c)
{
    std::ranges::transform(a, b, std::begin(c),
                           [](auto const a, auto const b) { return a + b; });


}

当我尝试像下面这样称呼它时:

std::array<int, 10> a{};
std::array<int, 10> b{};
std::array<int, 10> c{};

// more initialisation for a, b, and c
// ...

sum(a, b, c);

我收到以下模板扣分错误:

<source>:41:5: error: no matching function for call to 'sum'
    sum(a, b, c);
        ^~~
<source>:15:10: note: candidate template ignored: could not match 'span' against 'array'
    auto sum(span_const_of_const<T, N> a, 
             ^

我需要用显式构造函数修复调用,如下所示:std::span

sum(std::span(a), std::span(b), std::span(c));

我的印象是,这意味着我不必这样做。我在这里做错了什么?std::span

C 模板 ++20 C ++-概念 std-span

评论

0赞 Jarod42 9/13/2023
array即使可转换为。span
0赞 Marek R 9/13/2023
完成模板推导时,它必须是完全匹配的(无转换)。由于您使用的是 C++20,因此只需使用 concept 来解决此问题。
0赞 HolyBlackCat 9/13/2023
参与模板参数推导的函数参数拒绝执行任何隐式转换。接受 ,然后投射到自己身上。T &&
0赞 Jarod42 9/13/2023
span<int>顺便说一句,这将是 2 个有效匹配;-)span<int, 10>
0赞 Caleth 9/13/2023
你可能想穿上requires N != std::dynamic_extentsum

答:

2赞 Caleth 9/13/2023 #1

模板参数推导不考虑转换。如果不推导出参数,则不必指定 span。

sum<int, 10>(a, b, c);

或者,您可以推导出参数并约束它们以允许构造std::span<arithmetic, N>

template <typename T>
concept arithmetic_span_like = std::ranges::range<T> 
    && arithmetic<std::ranges::range_value_t<T>> 
    && std::constructible_from<std::span<std::ranges::range_value_t<T>>, T>;

template <typename A, typename B>
concept same_size = arithmetic_span_like<A> 
    && arithmetic_span_like<B>
    && requires(A a, B b)
{
    std::ranges::size(a) == std::ranges::size(b);
};

template <arithmetic_span_like A, arithmetic_span_like B, arithmetic_span_like C>
requires same_size<A, B> && same_size<A, C>
auto sum(A&& a, B&& b, C&& c)
{
    std::ranges::transform(a, b, std::begin(c), std::plus{});
}

Godbolt 链接