背景
所以,我的理解是,演绎指南只对构造函数起作用,当模板类型值不能自动知道时,它可以帮助自动推导出构造函数类型的模板参数。
在我自己的span类中,我试图从我的类构造函数中为rvalue std::array(和任何rvalue连续序列)自动推导我的类模板参数,即my_span{std::array{1,2,3}}
工作。
在遇到这个问题之后,我意识到GCC和MSVC似乎都不允许这个与std::span
一起工作。为了清楚,作为函数参数传递,或者显式指定std::span类型都可以。它似乎无法从右值为std::array
的构造函数调用自动创建std::span<const T>
。
我不得不加倍尝试,试图弄清楚你是否可以在原始构造函数调用上使用演绎,但在here给出的示例中,它被清楚地概述了。下面演示了与我要求的类似的功能。
// declaration of the template
template<class T>
struct container
{
container(T t) {}
template<class Iter>
container(Iter beg, Iter end);
};
// additional deduction guide
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
// uses
container c(7); // OK: deduces T=int using an implicitly-generated guide
std::vector<double> v = {/* ... */};
auto d = container(v.begin(), v.end()); // OK: deduces T=double
container e{5, 6}; //
字符串
错误
我的理解是C++标准中概述的以下推论应该适用:
template< class T, std::size_t N >
span( const std::array<T, N>& ) -> span<const T, N>;
型
但是,这在GCC和MSVC上都失败了。
#include<span>
#include <vector>
#include <array>
void p(std::span<const int> s) {
}
int main(){
std::vector<int> init = {1,2,3,4};
std::span<int> x;
p(std::array<int, 3>{1,2,3}); //works
p({std::array{1,2,3}}); //works
auto std_span_0 = std::span(std::array{1,2,3}); //doesn't work compile errro
std::span std_span_1(std::array{1,2,3}) //doesn't work compile error
return 0;
}
型
GCC错误
<source>:12:22: error: no matching conversion for functional-style cast from 'std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>' (aka 'array<int, 1 + sizeof...(_Up)>') to 'std::span<remove_reference_t<ranges::range_reference_t<array<int, 3> &>>>' (aka 'span<int>')
12 | auto std_span_0 = std::span(std::array{1,2,3});
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:194:2: note: candidate constructor [with _Tp = int, _ArrayExtent = 3] not viable: expects an lvalue for 1st argument
194 | span(array<_Tp, _ArrayExtent>& __arr) noexcept
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:225:7: note: candidate constructor not viable: no known conversion from 'std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>' (aka 'array<int, 1 + sizeof...(_Up)>') to 'const span<int>' for 1st argument
225 | span(const span&) noexcept = default;
| ^ ~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:187:2: note: candidate template ignored: could not match 'type_identity_t<element_type>[_ArrayExtent]' (aka 'int[_ArrayExtent]') against 'std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>' (aka 'array<int, 1 + sizeof...(_Up)>')
187 | span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:201:2: note: candidate template ignored: constraints not satisfied [with _Tp = int, _ArrayExtent = 3]
201 | span(const array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:199:11: note: because '__is_compatible_array<const int, 3UL>::value' evaluated to false
199 | requires __is_compatible_array<const _Tp, _ArrayExtent>::value
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:213:2: note: candidate template ignored: constraints not satisfied [with _Range = std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>]
213 | span(_Range&& __range)
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:207:8: note: because '!__detail::__is_std_array<remove_cvref_t<array<int, 3> > >' evaluated to false
207 | && (!__detail::__is_std_array<remove_cvref_t<_Range>>)
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:233:2: note: candidate template ignored: could not match 'span' against 'array'
233 | span(const span<_OType, _OExtent>& __s) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:149:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
149 | span() noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:157:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
157 | span(_It __first, size_type __count)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:172:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
172 | span(_It __first, _End __last)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
<source>:13:14: error: no matching constructor for initialization of 'std::span<remove_reference_t<ranges::range_reference_t<array<int, 3> &>>>' (aka 'span<int>')
13 | std::span std_span_1(std::array{1,2,3});
| ^ ~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:194:2: note: candidate constructor [with _Tp = int, _ArrayExtent = 3] not viable: expects an lvalue for 1st argument
194 | span(array<_Tp, _ArrayExtent>& __arr) noexcept
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:225:7: note: candidate constructor not viable: no known conversion from 'std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>' (aka 'array<int, 1 + sizeof...(_Up)>') to 'const span<int>' for 1st argument
225 | span(const span&) noexcept = default;
| ^ ~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:187:2: note: candidate template ignored: could not match 'type_identity_t<element_type>[_ArrayExtent]' (aka 'int[_ArrayExtent]') against 'std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>' (aka 'array<int, 1 + sizeof...(_Up)>')
187 | span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:201:2: note: candidate template ignored: constraints not satisfied [with _Tp = int, _ArrayExtent = 3]
201 | span(const array<_Tp, _ArrayExtent>& __arr) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:199:11: note: because '__is_compatible_array<const int, 3UL>::value' evaluated to false
199 | requires __is_compatible_array<const _Tp, _ArrayExtent>::value
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:213:2: note: candidate template ignored: constraints not satisfied [with _Range = std::array<enable_if_t<is_same_v<int, int> && is_same_v<int, int>, int>, 1 + sizeof...(_Up)>]
213 | span(_Range&& __range)
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:207:8: note: because '!__detail::__is_std_array<remove_cvref_t<array<int, 3> > >' evaluated to false
207 | && (!__detail::__is_std_array<remove_cvref_t<_Range>>)
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:233:2: note: candidate template ignored: could not match 'span' against 'array'
233 | span(const span<_OType, _OExtent>& __s) noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:149:7: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
149 | span() noexcept
| ^
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:157:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
157 | span(_It __first, size_type __count)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/14.0.0/../../../../include/c++/14.0.0/span:172:2: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
172 | span(_It __first, _End __last)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
2 errors generated.
Compiler returned: 1
型
它并没有真正解释为什么构造函数在这里被拒绝。
MSVC同样失败:
example.cpp
<source>(12): error C2440: '<function-style-cast>': cannot convert from 'std::array<int,3>' to 'std::span<int,18446744073709551615>'
<source>(12): note: 'std::span<int,18446744073709551615>::span': no overloaded function could convert all the argument types
C:/data/msvc/14.39.33321-Pre/include\span(358): note: could be 'std::span<int,18446744073709551615>::span<int,3>(std::array<int,3> &) noexcept'
<source>(12): note: 'std::span<int,18446744073709551615>::span<int,3>(std::array<int,3> &) noexcept': cannot convert argument 1 from 'std::array<int,3>' to 'std::array<int,3> &'
<source>(12): note: A non-const reference may only be bound to an lvalue
C:/data/msvc/14.39.33321-Pre/include\span(379): note: or 'std::span<int,18446744073709551615>::span(const std::span<_OtherTy,_OtherExtent> &) noexcept'
C:/data/msvc/14.39.33321-Pre/include\span(366): note: or 'std::span<int,18446744073709551615>::span(_Rng &&)'
C:/data/msvc/14.39.33321-Pre/include\span(363): note: or 'std::span<int,18446744073709551615>::span(const std::array<_OtherTy,_Size> &) noexcept'
C:/data/msvc/14.39.33321-Pre/include\span(353): note: or 'std::span<int,18446744073709551615>::span(int (&)[_Size]) noexcept'
C:/data/msvc/14.39.33321-Pre/include\span(339): note: or 'std::span<int,18446744073709551615>::span(_It,_Sentinel) noexcept(<expr>)'
C:/data/msvc/14.39.33321-Pre/include\span(328): note: or 'std::span<int,18446744073709551615>::span(_It,std::span<int,18446744073709551615>::size_type) noexcept'
<source>(12): note: while trying to match the argument list '(std::array<int,3>)'
<source>(13): error C2665: 'std::span<int,18446744073709551615>::span': no overloaded function could convert all the argument types
C:/data/msvc/14.39.33321-Pre/include\span(358): note: could be 'std::span<int,18446744073709551615>::span<int,3>(std::array<int,3> &) noexcept'
<source>(13): note: 'std::span<int,18446744073709551615>::span<int,3>(std::array<int,3> &) noexcept': cannot convert argument 1 from 'std::array<int,3>' to 'std::array<int,3> &'
<source>(13): note: A non-const reference may only be bound to an lvalue
C:/data/msvc/14.39.33321-Pre/include\span(379): note: or 'std::span<int,18446744073709551615>::span(const std::span<_OtherTy,_OtherExtent> &) noexcept'
<source>(13): note: 'std::span<int,18446744073709551615>::span(const std::span<_OtherTy,_OtherExtent> &) noexcept': could not deduce template argument for 'const std::span<_OtherTy,_OtherExtent> &' from 'std::array<int,3>'
C:/data/msvc/14.39.33321-Pre/include\span(366): note: or 'std::span<int,18446744073709551615>::span(_Rng &&)'
<source>(13): note: the associated constraints are not satisfied
C:/data/msvc/14.39.33321-Pre/include\span(365): note: the concept 'std::_Span_compatible_range<std::array<int,3>,int>' evaluated to false
C:/data/msvc/14.39.33321-Pre/include\span(254): note: the constraint was not satisfied
C:/data/msvc/14.39.33321-Pre/include\span(363): note: or 'std::span<int,18446744073709551615>::span(const std::array<_OtherTy,_Size> &) noexcept'
<source>(13): note: the associated constraints are not satisfied
C:/data/msvc/14.39.33321-Pre/include\span(362): note: the constraint was not satisfied
C:/data/msvc/14.39.33321-Pre/include\span(353): note: or 'std::span<int,18446744073709551615>::span(int (&)[_Size]) noexcept'
<source>(13): note: 'std::span<int,18446744073709551615>::span(int (&)[_Size]) noexcept': could not deduce template argument for 'int (&)[_Size]' from 'std::array<int,3>'
C:/data/msvc/14.39.33321-Pre/include\span(339): note: or 'std::span<int,18446744073709551615>::span(_It,_Sentinel) noexcept(<expr>)'
<source>(13): note: 'std::span<int,18446744073709551615>::span(_It,_Sentinel) noexcept(<expr>)': expects 2 arguments - 1 provided
C:/data/msvc/14.39.33321-Pre/include\span(328): note: or 'std::span<int,18446744073709551615>::span(_It,std::span<int,18446744073709551615>::size_type) noexcept'
<source>(13): note: 'std::span<int,18446744073709551615>::span(_It,std::span<int,18446744073709551615>::size_type) noexcept': expects 2 arguments - 1 provided
<source>(13): note: while trying to match the argument list '(std::array<int,3>)'
Compiler returned: 2
型
提问
有人能告诉我如何让像auto x = custom_span(std::array{1,2,3}}
这样的东西通过ctad正确地产生custom_span<const int, 3>
吗?
2条答案
按热度按时间lqfhib0f1#
这对
std::span
不起作用的原因是最后列出的扣除指南用于https://en.cppreference.com/w/cpp/container/span/deduction_guides:字符串
对于
R = std::array<int, 3>
,右值std::array<int, 3>
与R&&
的匹配比转换为const std::array<int, 3>&
更好。这意味着
std::span(std::array{1,2,3})
推导出int
对应T
,而不是const int
(以及std::dynamic_extent
而不是3
对应的区段),右值数组不能转换为const int
。如果有一个推理指南,比如:
型
这将允许
std::span(std::array{1, 2, 3})
(成为std::span<const int, 3>(std::array{1, 2, 3})
)。但这可能不可取,因为数组立即被销毁,留下一个悬空引用。j7dteeu82#
仅凭演绎指南
字符串
它按预期工作Demo
问题是constructors of span比唯一显示的签名更受限制。
型
还有一条注解:
只有当
extent == std::dynamic_extent || N == extent
为true并且从std::remove_pointer_t<decltype(data(arr))>
到element_type的转换至多是限定转换时,这些重载才会参与重载解析。error表示“extra”概念失败:
“std::_Span_compatible_rangestd::array<int,3,int>”的概念被评估为false
拒绝预期的构造函数。