我正在使用 Boost 1.78,并且我正在尝试使用它的
std::span
实现。虽然 Span 实现似乎很好,但当我在 Span 上调用 boost::begin()
时,如果该 Span 是右值,它会返回一个 const 指针,这会破坏重要的用例,例如:
boost::fill( returns_a_span(), 0 );
测试程序(无法编译 - 有趣的是错误消息)是:
#include <vector>
#include <boost/core/span.hpp>
#include <boost/range/begin.hpp>
template <typename T>
struct ErrorType;
int main() {
std::vector<unsigned char> vec{ 1, 2, 3, 4, 5 };
boost::span<unsigned char> sp{ vec };
ErrorType< decltype( std::begin(sp) ) > e1;
ErrorType< decltype( std::begin(std::move(sp)) ) > e2;
ErrorType< decltype( boost::begin(sp) ) > e3;
ErrorType< decltype( boost::begin(std::move(sp)) ) > e4;
ErrorType< decltype( sp.begin() ) > e5;
ErrorType< decltype( std::move(sp).begin() ) > e6;
return 0;
}
编译器的输出是:
spantest.cc: In function int main():
spantest.cc:13:44: error: aggregate ErrorType<unsigned char*> e1 has incomplete type and cannot be defined
ErrorType< decltype( std::begin(sp) ) > e1;
^~
spantest.cc:14:55: error: aggregate ErrorType<unsigned char*> e2 has incomplete type and cannot be defined
ErrorType< decltype( std::begin(std::move(sp)) ) > e2;
^~
spantest.cc:15:46: error: aggregate ErrorType<unsigned char*> e3 has incomplete type and cannot be defined
ErrorType< decltype( boost::begin(sp) ) > e3;
^~
spantest.cc:16:57: error: aggregate ErrorType<const unsigned char*> e4 has incomplete type and cannot be defined
ErrorType< decltype( boost::begin(std::move(sp)) ) > e4;
^~
spantest.cc:17:40: error: aggregate ErrorType<unsigned char*> e5 has incomplete type and cannot be defined
ErrorType< decltype( sp.begin() ) > e5;
^~
spantest.cc:18:51: error: aggregate ErrorType<unsigned char*> e6 has incomplete type and cannot be defined
ErrorType< decltype( std::move(sp).begin() ) > e6;
类型不完整这一事实是预料之中的——我只是用它作为让编译器告诉我类型是什么的一种方式。有趣的是 e4 - 右值跨度上的
boost::begin()
返回一个 const 指针,即使该方法不返回 (e6) 且 std::begin()
不返回 (e2)。这只是boost::begin()
中的一个错误,还是我误解了什么?除了始终使用左值之外,还有其他解决方法吗?
看起来这个问题与std::begin和R-values密切相关,但
std::begin()
似乎不再有问题,但boost::begin()
有。然而,提升范围算法显式调用 boost::begin()
,因此它们似乎不适用于非常量数据的跨度。
我理解,如果使用右值调用
boost::begin()
并且不存在右值重载,则它可以使用 const 左值引用。我不明白的是为什么 boost::span
与任何其他迭代器范围不同 - boost 范围算法始终传递右值范围,但我以前从未见过这一点。
看起来整个问题是您正在实例化不完整的
ErrorType
实例。
为了简洁起见,让我们将其重命名为
E
并实际定义它!
template <typename> struct E{};
现在一切都编译好了:https://godbolt.org/z/E78qh8c75
#include <boost/core/span.hpp>
#include <boost/range/begin.hpp>
#include <vector>
template <typename> struct E{};
int main() {
std::vector<unsigned char> vec{1, 2, 3, 4, 5};
boost::span<unsigned char> sp{vec};
E<decltype(std::begin(sp))> e1;
E<decltype(std::begin(std::move(sp)))> e2;
E<decltype(boost::begin(sp))> e3;
E<decltype(boost::begin(std::move(sp)))> e4;
E<decltype(sp.begin())> e5;
E<decltype(std::move(sp).begin())> e6;
}