#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));
}
Run Code Online (Sandbox Code Playgroud)
在此代码中,我希望 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 );
Run Code Online (Sandbox Code Playgroud)
然而,由于某种原因,它们似乎都打印了完整的跨度,而不是我期望的 3 个元素。调用 subspan 方法的变体 3 确实给出了预期的结果。
使用 GCC、Clang 和 Clang+libc++ 的代码输出:
#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));
}
Run Code Online (Sandbox Code Playgroud)
据我所知,两者都应该是连续迭代器,结束迭代器是起始迭代器的 sized_sentinel_(因为它是相同的类型),迭代器返回的引用类型(int &)的转换是给定的元素类型限定转换和迭代器/指针不可转换为 size_t (请参阅 static_assert)。
因此,从我可以推断的一切来看,应该选择提到的构造函数并给我预期的效果。你能解释一下为什么不可以吗?
相关问题:
在您的示例中,变量的类型span为span<int, 9>,因此 for createSubSpan1/2(),TSpan将被推导为span<int, 9>,这保证返回的跨度具有9元素。换句话说,你必须确保它stop - start是准确的9,否则你将得到 UB ( [span.cons#8] )。
至于createSubSpan3(),由于subspan()返回span<int, dynamic_extent>,构造的span的元素个数正好是stop - start。
| 归档时间: |
|
| 查看次数: |
199 次 |
| 最近记录: |