如下面的代码所示,我可以使用
std::ranges::sort
对压缩向量进行排序,使用 lambda 指定应由第一个向量完成排序。有没有一种方法可以使用投影,指定元组字段名称(或其他名称),如示例(2)和(3)所示?
示例 (2) 在 range3 中工作,其中元素被实现为
std::pair
(或者至少可以通过这种方式访问它)。现在有了标准库范围,它是用元组实现的,这种方法不起作用。
我可以在没有 lambda 的情况下完成这个任务吗?
我为什么关心?我需要保留单独且可用的比较器和投影,以便与我的调整版本一起使用。额外的好处是代码更少,更容易编写、阅读和支持。
#include <algorithm>
#include <ranges>
#include <vector>
int main()
{
std::vector<float> x_values = { 3.0f, 1.0f, 2.0f };
std::vector<float> y_values = { 5.0f, 6.0f, 7.0f };
// (1) Compiles
std::ranges::sort(std::ranges::views::zip(x_values, y_values), [](const auto& lhs, const auto& rhs) {
return std::get<0>(lhs) < std::get<0>(rhs);
});
// (2) Doesn't compile since in ranges they use tuples
std::ranges::sort(std::ranges::views::zip(x_values, y_values), std::less<>{}, &std::pair<int, int>::first);
// (3) I guess doesn't compile since get is a member function template, not a member field
std::ranges::sort(std::ranges::views::zip(x_values, y_values), std::less<>{}, &std::get<0>);
}
这是演示。
尝试 (2) 给出错误消息:
In file included from <source>:2:
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4558:14: error: type constraint differs in template redeclaration
4558 | template<copy_constructible _Fp, input_range... _Ws>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4458:14: note: in instantiation of template class 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::_Iterator<true>' requested here
4458 | { return _Iterator<true>(__detail::__tuple_transform(ranges::begin, _M_views)); }
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:23: note: in instantiation of member function 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::begin' requested here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:6: note: in instantiation of requirement here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:977:32: note: while substituting template arguments into constraint expression here
977 | concept __member_begin = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
978 | {
| ~
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
980 | };
| ~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: while checking the satisfaction of concept '__member_begin<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>> &>' requested here
112 | requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
| ^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: (skipping 4 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:501:21: note: while substituting template arguments into constraint expression here
501 | concept range = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
502 | {
| ~
503 | ranges::begin(__t);
| ~~~~~~~~~~~~~~~~~~~
504 | ranges::end(__t);
| ~~~~~~~~~~~~~~~~~
505 | };
| ~
...
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:635:33: note: because '*__i' would be invalid: indirection requires pointer operand ('std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>' invalid)
635 | = requires(_Iter __i) { { *__i } -> __detail::__can_reference; }
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_algo.h:1794:7: note: candidate template ignored: constraints not satisfied [with _Range = zip_view<all_t<vector<float, allocator<float>> &>, all_t<vector<float, allocator<float>> &>>, _Comp = std::less<>, _Proj = int std::pair<int, int>::*]
1794 | operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_algo.h:1792:16: note: because 'sortable<iterator_t<zip_view<ref_view<vector<float, allocator<float> > >, ref_view<vector<float, allocator<float> > > > >, std::less<void>, int std::pair<int, int>::*>' evaluated to false
1792 | requires sortable<iterator_t<_Range>, _Comp, _Proj>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:950:43: note: because substituted constraint expression is ill-formed: constraints not satisfied for alias template 'projected' [with _Iter = std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::_Iterator<true>, _Proj = int std::pair<int, int>::*]
950 | && indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>;
| ^
3 errors generated.
Compiler returned: 1
尝试 (3) 给出错误消息:
In file included from <source>:2:
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4558:14: error: type constraint differs in template redeclaration
4558 | template<copy_constructible _Fp, input_range... _Ws>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4458:14: note: in instantiation of template class 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::_Iterator<true>' requested here
4458 | { return _Iterator<true>(__detail::__tuple_transform(ranges::begin, _M_views)); }
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:23: note: in instantiation of member function 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::begin' requested here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:6: note: in instantiation of requirement here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:977:32: note: while substituting template arguments into constraint expression here
977 | concept __member_begin = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
978 | {
| ~
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
980 | };
| ~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: while checking the satisfaction of concept '__member_begin<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>> &>' requested here
112 | requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
| ^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: (skipping 4 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:501:21: note: while substituting template arguments into constraint expression here
501 | concept range = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
502 | {
| ~
503 | ranges::begin(__t);
| ~~~~~~~~~~~~~~~~~~~
504 | ranges::end(__t);
| ~~~~~~~~~~~~~~~~~
505 | };
| ~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:1059:12: note: while checking the satisfaction of concept 'range<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>>' requested here
1059 | template<range _Range>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:1059:12: note: while substituting template arguments into constraint expression here
1059 | template<range _Range>
| ^~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_algo.h:1793:17: note: while checking constraint satisfaction for template 'borrowed_iterator_t<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>>' required here
1793 | constexpr borrowed_iterator_t<_Range>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:11:19: note: while substituting deduced template arguments into function template 'operator()' [with _Range = zip_view<all_t<vector<float, allocator<float>> &>, all_t<vector<float, allocator<float>> &>>, _Comp = (lambda at <source>:11:65), _Proj = (no value)]
11 | std::ranges::sort(std::ranges::views::zip(x_values, y_values), [](const auto& lhs, const auto& rhs) {
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4829:12: note: previous template declaration is here
4829 | template<copy_constructible _Fp, input_range... _Vs>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4558:14: error: type constraint differs in template redeclaration
4558 | template<copy_constructible _Fp, input_range... _Ws>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/ranges:4458:30: note: in instantiation of template class 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::_Iterator<false>' requested here
4458 | { return _Iterator<true>(__detail::__tuple_transform(ranges::begin, _M_views)); }
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:23: note: in instantiation of member function 'std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::begin' requested here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:979:6: note: in instantiation of requirement here
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:977:32: note: while substituting template arguments into constraint expression here
977 | concept __member_begin = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
978 | {
| ~
979 | { __decay_copy(__t.begin()) } -> input_or_output_iterator;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
980 | };
| ~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: while checking the satisfaction of concept '__member_begin<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>> &>' requested here
112 | requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
| ^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:112:50: note: (skipping 4 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:501:21: note: while substituting template arguments into constraint expression here
501 | concept range = requires(_Tp& __t)
| ^~~~~~~~~~~~~~~~~~
502 | {
| ~
503 | ranges::begin(__t);
| ~~~~~~~~~~~~~~~~~~~
504 | ranges::end(__t);
| ~~~~~~~~~~~~~~~~~
505 | };
| ~
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_base.h:1059:12: note: while checking the satisfaction of concept 'range<std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>>' requested here
1059 | template<range _Range>
| ^
...
635 | = requires(_Iter __i) { { *__i } -> __detail::__can_reference; }
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_algo.h:1794:7: note: candidate template ignored: constraints not satisfied [with _Range = zip_view<all_t<vector<float, allocator<float>> &>, all_t<vector<float, allocator<float>> &>>, _Comp = std::less<>, _Proj = __enable_if_t<(0UL >= sizeof...(_Elements))> (*)(const tuple<> &)]
1794 | operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/ranges_algo.h:1792:16: note: because 'sortable<iterator_t<zip_view<ref_view<vector<float, allocator<float> > >, ref_view<vector<float, allocator<float> > > > >, std::less<void>, void (*)(const std::tuple<> &)>' evaluated to false
1792 | requires sortable<iterator_t<_Range>, _Comp, _Proj>
| ^
/opt/compiler-explorer/gcc-13.2.0/lib/gcc/x86_64-linux-gnu/13.2.0/../../../../include/c++/13.2.0/bits/iterator_concepts.h:950:43: note: because substituted constraint expression is ill-formed: constraints not satisfied for alias template 'projected' [with _Iter = std::ranges::zip_view<std::ranges::ref_view<std::vector<float>>, std::ranges::ref_view<std::vector<float>>>::_Iterator<true>, _Proj = void (*)(const std::tuple<> &)]
950 | && indirect_strict_weak_order<_Rel, projected<_Iter, _Proj>>;
| ^
5 errors generated.
Compiler returned: 1
(如果您知道如何在这里折叠或缩小错误日志的字段,请告诉我或更新问题;我看到它们太大,但看不到调整的方法)。
我需要保留单独且可用的比较器和投影,以便与我的调整版本一起使用。额外的好处是代码更少,更容易编写、阅读和支持。
我对老式函子的看法,可自定义如下:
template<std::size_t N>
struct Get {
template<typename T>
constexpr auto operator()(const T& tuple) const {
return std::get<N>(tuple);
}
};
现在你可以写:
auto zipped = std::views::zip(x_values, y_values, z_values);
// Sort by first element (x_values)
std::ranges::sort(zipped, std::less{}, Get<0>{});
// Or ...sort by second element (y_values)
std::ranges::sort(zipped, std::less{}, Get<1>{});
// so on...
````