#include <iostream>
#include <span>
#include <string>
#include <string_view>
#include <vector>
namespace {
template <typename TSpan>
auto createSubSpan1(TSpan &, typename TSpan::iterator start,
typename TSpan::iterator stop) {
static_assert(!std::is_convertible_v<typename TSpan::iterator, std::size_t>);
return TSpan{start, stop};
}
template <typename TSpan>
auto createSubSpan2(TSpan &span, typename TSpan::iterator start,
typename TSpan::iterator stop) {
auto startOffset = std::distance(span.begin(), start);
auto stopOffset = std::distance(span.begin(), stop);
std::cout << startOffset << "-" << stopOffset << std::endl;
static_assert(!std::is_convertible_v<decltype(span.data() + startOffset), std::size_t>);
return TSpan{span.data() + startOffset, span.data() + stopOffset};
}
template <typename TSpan>
auto createSubSpan3(TSpan &span, typename TSpan::iterator start,
typename TSpan::iterator stop) {
return span.subspan(static_cast<size_t>(std::distance(span.begin(), start)),
static_cast<size_t>(std::distance(start, stop)));
}
template <typename TSpan>
auto printSpan(std::string_view header, TSpan span) {
std::cout << header << std::endl;
for (const auto &element : span) std::cout << "\t" << element << std::endl;
}
} // namespace
int main() {
int a[]{0, 1, 2, 3, 4, 5, 6, 7, 8};
auto span = std::span{a};
std::vector<int> vector{11, 12, 13};
auto beginIt = span.begin();
auto endIt = std::move(vector.begin(), vector.end(), beginIt);
printSpan("incorrect (iterator)", createSubSpan1(span, beginIt, endIt));
printSpan("incorrect (pointer)", createSubSpan2(span, beginIt, endIt));
printSpan("correct", createSubSpan3(span, beginIt, endIt));
}
code at compiler-explorer
在这段代码中,我希望createSubSpan1/2方法调用https://en.cppreference.com/w/cpp/container/span/span的构造函数(3
template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );
然而,由于某种原因,它们似乎都打印了完整的span,而不是我所期望的3个元素。变量3调用subspan方法确实给出了预期的结果。
使用GCC、Clang和Clang + libc ++的代码输出:
incorrect (iterator)
11
12
13
3
4
5
6
7
8
0-3
incorrect (pointer)
11
12
13
3
4
5
6
7
8
correct
11
12
13
据我所知,两者都应该是contiguous_iterator,结束迭代器是开始迭代器的size_sentinel_(因为它是相同的类型),迭代器返回的引用类型(int &)的转换是给定限定转换的元素类型,并且迭代器/指针不能转换为size_t(参见static_assert)。
所以从我所能推断的一切来看,上面提到的构造函数应该被选择并给我预期的效果。你能解释一下为什么没有吗?
相关问题:
- https://stackoverflow.com/a/64187250/2466431:答案表明此构造函数应该与GCC和Clang一起使用。
1条答案
按热度按时间dsekswqp1#
在您的示例中,
span
变量的类型是span<int, 9>
,因此对于createSubSpan1/2()
,TSpan
将被推导为span<int, 9>
,这保证了返回的span具有9
元素,换句话说,您必须确保stop - start
正好是9
,否则您将得到UB([span.cons#8])。对于
createSubSpan3()
,由于subspan()
返回span<int, dynamic_extent>
,因此构造的span的元素数正好是stop - start
。