c – 如何正确转发Invocable类型

前端之家收集整理的这篇文章主要介绍了c – 如何正确转发Invocable类型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我真的很喜欢使用 cmcstl2,Ranges TS的实现.我特别喜欢每个STL算法的可选投影.可调用类型转发(嗯……或不),如下所示:( min_element.hpp)
template <ForwardIterator I,Sentinel<I> S,class Comp = less<>,class Proj = identity>
requires
    IndirectStrictWeakOrder<
        Comp,projected<I,Proj>>()
I min_element(I first,S last,Comp comp = Comp{},Proj proj = Proj{});

template <ForwardRange Rng,projected<iterator_t<Rng>,Proj>>()
safe_iterator_t<Rng>
min_element(Rng&& rng,Proj proj = Proj{})
{
    return __stl2::min_element(__stl2::begin(rng),__stl2::end(rng),__stl2::ref(comp),__stl2::ref(proj));
}

作为参考:range-v3库实现如下:(min_element.hpp)

struct min_element_fn {
        template<typename I,typename S,typename C = ordered_less,typename P = ident,CONCEPT_REQUIRES_(ForwardIterator<I>() && Sentinel<S,I>() &&
                IndirectRelation<C,P>>())>
        I operator()(I begin,S end,C pred = C{},P proj = P{}) const;

        template<typename Rng,typename I = range_iterator_t<Rng>,CONCEPT_REQUIRES_(ForwardRange<Rng>() &&
                IndirectRelation<C,P>>())>
        range_safe_iterator_t<Rng> operator()(Rng &&rng,P proj = P{}) const
        {
            return (*this)(begin(rng),end(rng),std::move(pred),std::move(proj));
        }
};

现在我试着理解两种方法的区别和推理.
为什么我要按值使用Invocable类型呢?
为什么我不应该为这些类型使用完美转发?

我比第一种方法更了解第二种方法,因为我理解按值获取接收参数的方法.

解决方法

两个原因:

>我对标准库规范的阅读是算法可以根据需要多次复制用户函数对象,但是被指定在单个实例上执行所有调用.由于cmcstl2经常根据其他算法实现算法,因此满足该要求的最简单方法是通过reference_wrapper在内部传递函数对象.例如,binary_search调用lower_bound,然后确定由下限表示的元素是否完全匹配.它将reference_wrappers传递给compare_bound并将项目函数对象传递给lower_bound,以便稍后可以调用相同的实例.
>大型和/或可变功能对象可能很少见,但没有理由在标准库中必须支持它们.复制通常很便宜,并且移动几乎总是如此,但通过引用传递“从不”昂贵. cmcstl2最小化两个副本的用户功能对象的移动. (“never”上的空中引号表示,如果别名分析被函数对象引用混淆,那么通过引用传递会给优化器带来更大的负载,增加编译时间并可能在极端情况下生成较差的代码.)

这种推理有一些明显的漏洞.对我来说最重要的是“如果函数对象可能是有用的,那么算法不应该返回它们以保留该状态,std :: for_each也是如此?” cmcstl2的设计基本上违反了编程元素所谓的“有用回归定律”.我们是否应该使标准算法的签名复杂化以返回多达三个函数对象 – 比如比较器和两个投影 – 以容纳0.1%的用例?我认为这里显而易见的答案是“不”,特别是考虑到解决方法很简单:传递一个reference_wrapper.

那么,为什么cmcstl2一般 – 以及标准C的std :: for_each特别是 – 当解决方法类似于传递reference_wrapper时,它们会不会适应大型和/或可变函数对象?似乎cmcstl2的设计者在这里犯了同样的错误,就像LWG让std :: for_each返回它的函数对象一样.

猜你在找的C&C++相关文章