Apple Clang下使用迭代器对构造std::span失败的编译问题
Apple Clang 环境下迭代器构造std::span编译失败问题
问题背景
实现函数时通过const引用接收level_state类型对象,该对象包含std::vector<unsigned short>类型的成员floor_datas,需要为该vector的指定范围构造std::span<const unsigned short>。代码在多数新版本编译器环境下可正常编译,但在Apple Clang搭配macOS 12.3及更早版本SDK的libc++环境下编译报错。
复现代码
#include <span> #include <vector> #include <cstddef> struct level_state { std::vector<unsigned short> floor_datas; }; struct room_info { std::vector<std::size_t> floor; }; unsigned short get_floor_data_count(const unsigned short header) { return header & 0x3FFF; } std::span<const unsigned short> get_floor_data(const level_state& level, const room_info& room, const std::size_t sector_offset) { const std::size_t offset = room.floor[sector_offset]; const auto header = level.floor_datas[offset]; auto span = std::span(level.floor_datas.begin() + offset, level.floor_datas.begin() + offset + get_floor_data_count(header)); //assert_postcondition(((*(span.rbegin())) & 0x3FF) == 0x3FF, "Floor Data does not end with 0x3FFF"); return span; }
编译报错信息
[build] /.../floor_data.cpp:229:64: error: no matching constructor for initialization of 'std::span<const unsigned short, std::dynamic_extent>' [build] std::span<const unsigned short, std::dynamic_extent> span = std::span<const unsigned short, std::dynamic_extent>(level.floor_datas.begin() + offset, [build] ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:405:41: note: candidate constructor not viable: no known conversion from 'std::__wrap_iter<const unsigned short *>' to 'std::span<const unsigned short, 18446744073709551615>::pointer' (aka 'const unsigned short *') for 1st argument [build] _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __ptr, size_type __count) : __data{__ptr}, __size{__count} {} [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:406:41: note: candidate constructor not viable: no known conversion from 'std::__wrap_iter<const unsigned short *>' to 'std::span<const unsigned short, 18446744073709551615>::pointer' (aka 'const unsigned short *') for 1st argument [build] _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __f, pointer __l) : __data{__f}, __size{static_cast<size_t>(distance(__f, __l))} {} [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:424:19: note: candidate template ignored: requirement '__is_span_compatible_container<std::__wrap_iter<const unsigned short *>, const unsigned short, void>::value' was not satisfied [with _Container = std::__wrap_iter<const unsigned short *>] [build] constexpr span( _Container& __c, [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:430:19: note: candidate template ignored: requirement '__is_span_compatible_container<const std::__wrap_iter<const unsigned short *>, const unsigned short, void>::value' was not satisfied [with _Container = std::__wrap_iter<const unsigned short *>] [build] constexpr span(const _Container& __c, [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:437:19: note: candidate template ignored: could not match 'span' against '__wrap_iter' [build] constexpr span(const span<_OtherElementType, _OtherExtent>& __other, [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:402:15: note: candidate constructor not viable: requires 1 argument, but 2 were provided [build] constexpr span (const span&) noexcept = default; [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:410:15: note: candidate template not viable: requires single argument '__arr', but 2 arguments were provided [build] constexpr span(element_type (&__arr)[_Sz]) noexcept : __data{__arr}, __size{_Sz} {} [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:415:15: note: candidate template not viable: requires single argument '__arr', but 2 arguments were provided [build] constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:420:15: note: candidate template not viable: requires single argument '__arr', but 2 arguments were provided [build] constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} [build] ^ [build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/include/c++/v1/span:400:41: note: candidate constructor not viable: requires 0 arguments, but 2 were provided [build] _LIBCPP_INLINE_VISIBILITY constexpr span() noexcept : __data{nullptr}, __size{0} {} [build] ^ [build] 1 error generated.
问题原因
从报错信息可以确认,macOS 12.3 SDK配套的旧版本libc++存在实现缺陷:
- 该版本的
std::span仅支持接收原生指针(pointer类型)的(指针,长度)、(起始指针,结束指针)构造重载,没有实现C++20标准规定的迭代器对构造函数 - 旧版libc++中
std::vector的迭代器是封装类型std::__wrap_iter,无法隐式转换为原生指针,因此传入迭代器时匹配不到可用构造函数,触发编译错误。
修复方案
两种兼容旧版libc++的写法,任选其一即可:
- 手动取出vector的原生数据指针,用指针+长度的方式构造span,兼容性最好:
const auto* base_ptr = level.floor_datas.data() + offset; const auto count = get_floor_data_count(header); auto span = std::span<const unsigned short>(base_ptr, count); - 对迭代器调用
base()方法取出内部持有的原生指针(libc的__wrap_iter、GCC libstdc的vector迭代器均支持该方法):auto start = level.floor_datas.begin() + offset; auto end = start + get_floor_data_count(header); auto span = std::span<const unsigned short>(start.base(), end.base());
升级Xcode到14及以上版本、使用更新的macOS SDK后,新版libc++已经补全了迭代器对构造的支持,原写法可直接编译通过。
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

