给定这个程序,用 g++-13 -std=c++2b test.cpp
编译:
...那是哪里...
g++-13 (Debian 13-20230106-1) 13.0.0 20230106 (experimental) [master r13-5040-g53add162511]
#include <array>
#include <ranges>
auto
main() -> int
{
struct B { virtual void foo() = 0; };
struct D: B { virtual void foo() {} };
auto ds = std::array<D, 10>{};
auto to_b = [](D const& d) -> B const& { return d; };
auto bs = ds | std::views::transform(to_b);
for (auto& b: bs) {} // OK
auto zip = std::views::zip(ds, bs);
for (auto&& pair: zip) {} // error
return 0;
}
尝试循环 std::views::zip
其中压缩范围之一应该是对抽象基类的引用......只是不起作用。错误如下:
In file included from /usr/include/c++/13/bits/stl_algobase.h:64,
from /usr/include/c++/13/array:43,
from test.cpp:1:
/usr/include/c++/13/bits/stl_pair.h: In instantiation of ‘struct std::pair<main()::D, main()::B>’:
/usr/include/c++/13/type_traits:3744:12: recursively required by substitution of ‘template<class _Tp1, class _Tp2> struct std::__common_reference_impl<_Tp1&&, _Tp2&, 1, std::void_t<typename std::__common_ref_impl<_Tp1&&, _Tp2&, void>::type> > [with _Tp1 = std::pair<main()::D&, const main()::B&>; _Tp2 = std::pair<main()::D, main()::B>]’
/usr/include/c++/13/type_traits:3744:12: required from ‘struct std::common_reference<std::pair<main()::D&, const main()::B&>&&, std::pair<main()::D, main()::B>&>’
/usr/include/c++/13/type_traits:3724:11: required by substitution of ‘template<class ... _Tp> using std::common_reference_t = typename std::common_reference::type [with _Tp = {std::pair<main()::D&, const main()::B&>&&, std::pair<main()::D, main()::B>&}]’
/usr/include/c++/13/bits/iterator_concepts.h:324:13: required by substitution of ‘template<class _Iterator> requires (__iter_without_nested_types<_Iterator>) && (__cpp17_input_iterator<_Iterator>) struct std::__iterator_traits<_Iter, void> [with _Iterator = std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false>]’
/usr/include/c++/13/bits/stl_iterator_base_types.h:177:12: required from ‘struct std::iterator_traits<std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false> >’
/usr/include/c++/13/bits/iterator_concepts.h:211:4: required by substitution of ‘template<class _Iter, class _Tp> requires __primary_traits_iter<_Iter> struct std::__detail::__iter_traits_impl<_Iter, _Tp> [with _Iter = std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false>; _Tp = std::incrementable_traits<std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false> >]’
/usr/include/c++/13/bits/iterator_concepts.h:224:13: required by substitution of ‘template<class _Iter, class _Tp> using std::__detail::__iter_traits = typename std::__detail::__iter_traits_impl::type [with _Iter = std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false>; _Tp = std::incrementable_traits<std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false> >]’
/usr/include/c++/13/bits/iterator_concepts.h:227:13: required by substitution of ‘template<class _Tp> using std::__detail::__iter_diff_t = typename std::__detail::__iter_traits_impl<_Tp, std::incrementable_traits<_Iter> >::type::difference_type [with _Tp = std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false>]’
/usr/include/c++/13/bits/iterator_concepts.h:232:11: required by substitution of ‘template<class _Tp> using std::iter_difference_t = std::__detail::__iter_diff_t<typename std::remove_cvref<_Tp>::type> [with _Tp = std::ranges::zip_view<std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> > >::_Iterator<false>]’
/usr/include/c++/13/ranges:4436:26: required from ‘constexpr auto std::ranges::zip_view<_Vs>::end() requires !((__simple_view<_Vs> && ...)) [with _Vs = {std::ranges::ref_view<std::array<main()::D, 10> >, std::ranges::transform_view<std::ranges::ref_view<std::array<main()::D, 10> >, main()::<lambda(const main()::D&)> >}]’
test.cpp:18:20: required from here
/usr/include/c++/13/bits/stl_pair.h:194:11: error: cannot declare field ‘std::pair<main()::D, main()::B>::second’ to be of abstract type ‘main()::B’
194 | _T2 second; ///< The second member
| ^~~~~~
test.cpp:7:16: note: because the following virtual functions are pure within ‘main()::B’:
7 | struct B { virtual void foo() = 0; };
| ^
test.cpp:7:36: note: ‘virtual void main()::B::foo()’
7 | struct B { virtual void foo() = 0; };
这是正确的吗?我不认为我要求 std::pair<D, B>
;我想我要的是 std::pair<D&, B&>
。我不知道我在哪里或应该在哪里引起摘要 B
待 build 。如果我是...,我会完全理解这个错误,但是我...?
我已经阅读了 2 篇关于 std::views::zip
的标准论文以及围绕reference
问题的各种讨论和 value_type
,但我没有看到任何可以解释这一点的内容。
所以,要么我错过了标准论文和/或诊断中的一些关键细节(更有可能?)...或者libstdc++
中可能有一个小鬼。 (不太可能?)尝试实例化 pair<D, B>
当不需要时 - 不管怎样,我很感激来自更精通的人的输入:)
最佳答案
迭代器不仅仅有 reference
(不幸的是,因为并不总是语言引用),它们还有一个 value_type
。在 Ranges 中,很多模型都更加正式化。 C++20输入迭代器的核心概念是 indirectly_readable
,其中关键部分基本上是:
- 迭代器有
value_type
- 迭代器有
reference
,这是通过执行*ci
得到的类型在const I
上(注意const
。另请注意*i
和*ci
必须是相同的类型) reference&&
之间有一个共同的引用和value_type&
(注意&
)
您还可以看到其他要求,但这些是此处最相关的要求。通常(但并非总是),value_type
只是 remove_cvref_t<reference>
。并非如此的一种情况是 zip_view<Rs...>
,其中reference
是 tuple<range_reference_t<Rs>...>
和value_type
是 tuple<range_value_t<Rs>...>
.
现在,使用transform
例如,您有 reference
是 B&
和value_type
是 B
。这很好,因为常见的引用要求将使用 B&
(不是 B
),并且您没有做任何其他尝试构建 B
的事情(例如调用ranges::min
或其他)。
但是有了 zip
例如,假设我们实际上只是在做 zip(bs)
。在这里,reference
将是 tuple<B&>
,但是 value_type
是什么? ?嗯,它必须是 tuple<B>
,但你不能创建 tuple<B>
,所以这是格式不正确的(在实际的OP中它是 std::pair
,但最近进行了更改,始终使用 std::tuple
,这里的区别并不重要)。
那么,好吧,我们实际上能做什么?实际上没有另一个value_type
我们可以生产。重复利用tuple<B&>
是一个坏主意,这会破坏您使用的任何实际上想要具有值类型的算法。
唯一的选择是...没有 value_type
都在这里。有相当多的算法不使用 value_type
(其中最简单的就是您想要执行的 for
循环),并且不可否认,由于您没有使用的要求而无法支持这些算法,这有点糟糕。但这就是目前存在的设计,我认为很难改变。
所以解决方案实际上就是尝试避免 Abstract&
的范围。 Abstract*
会工作得很好,因为你最终会得到 value_type
的Abstract*
还。或reference_wrapper<Abstract>
,这至少可以表明您没有空指针。
关于当给定抽象基类的引用 View 时,C++23 std::views::zip 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75189622/