std::span
span<T>表示一段连续的内存,像数组一样,但它不拥有或管理这段内存,即它是“view”,大致上就是struct { T * ptr; size_t length; 一组获取内部元素的函数 },所以span具有三个特征:
- 连续内存
- 轻量级
- view
span的三个特征决定了它主要应用场合包括:
- C风格的(T *,size_t length)的包装器,这样,对C风格“数组”的操作,可以用C++容器类操作的风格来代替;
- 类似于string_view对string的作用,span<T>可以代替如vector<T>&这样的表达作为函数参数。
上面两点都可以提高代码的可读性和安全性。
下面是一个std::span的示例。
template<class T, std::size_t N> [[nodiscard]]
constexpr auto slide(std::span<T,N> s, std::size_t offset, std::size_t width) {
return s.subspan(offset, offset + width <= s.size() ? width : 0U);
}
template<class T> [[nodiscard]]
constexpr bool starts_with(std::span<T> data, std::span<T> prefix) {
return data.size() >= prefix.size()
&& std::equal(prefix.begin(), prefix.end(), data.begin());
}
template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool ends_with(std::span<T,N> data, std::span<T,M> suffix) {
return data.size() >= suffix.size()
&& std::equal(data.end() - suffix.size(), data.end(),
suffix.end() - suffix.size());
}
template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool contains(std::span<T,N> span, std::span<T,M> sub) {
return std::search(span.begin(), span.end(), sub.begin(), sub.end())
!= span.end();
}
void print(const auto& seq) {
for (const auto& elem : seq) std::cout << elem << ' ';
std::cout << '\n';
}
int main()
{
int a[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
std::vector<int> b={ 8, 7, 6 };
auto s1 = slide(std::span{a}, 3, 4);
print(s1);
std::cout<<starts_with(std::span(a,9), std::span(b.begin(), b.end()))<<std::endl;
std::cout<<ends_with(std::span{a}, std::span{a+6,3})<<std::endl;
std::cout<<contains(std::span{a}, std::span{a+1,4})<<std::endl;
}
上例中,通过span对数组的包装,使得对数组的操作完全变成了一种类似“集合”的操作。
std::bind_front
std::bind_front定义在<functional>中,与std::bind功能类似,都可以对函数进行包装,然后在方便的时候调用。
对于函数f(arg1,arg2…)
std::bind的用法是
在定义时,bindfun=std::bind(f,[arg,placeholder...]),arg和placeholder的总个数与f的参数一致;
使用时,bindfun([arg,..]),arg的个数与placeholder的个数一致,用以替代定义时的placeholder。
std::bind_front的用法是
在定义时,bindfun=std::bind_front(f,[arg…]),arg是f的前n个参数(n为0至f参数的个数,bind front的意思由此而来,就是绑定前n个参数);
使用时,bindfun([arg,…]),arg是剩余的f的参数。
void test_bind()
{
auto calc=[](int a, int b, int c) { return a+b-c;};
auto aa = std::bind_front(calc, 1,2);
std::cout << aa (3)<<"\n";
auto bb = std::bind_front(calc, 1,2,3);
std::cout << bb ()<<"\n";
auto cc=std::bind(calc, 1,std::placeholders::_2,std::placeholders::_1);
std::cout<<cc(3,2)<<"\n";
auto dd=std::bind(calc, std::placeholders::_1,std::placeholders::_2,3);
std::cout<<dd(1,2);
}
从上面的示例,如果仅按顺序bind调用,std::bind_front的写法要简单些,但使用placeholder占位符后,可以更灵活的方式“掩盖”原有的参数调用方式,std::bind_front就显得呆板些,而不能完成。