C++20新特性—span与bind_front

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就显得呆板些,而不能完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值