C++ 指针指向成员作为比较器的std算法;“关键”;
我经常发现自己使用C++ 指针指向成员作为比较器的std算法;“关键”;,c++,algorithm,c++11,pointer-to-member,C++,Algorithm,C++11,Pointer To Member,我经常发现自己使用std::sort,std::max_元素,以及类似的lambda来调用成员函数 std::vector<MyType> vec; // populate... auto m = std::max_element(std::begin(vec), std::end(vec), [](const MyType& a, const MyType& b) { return a.val() < b.val()}) 并按对象的val()s对对象
std::sort
,std::max_元素
,以及类似的lambda来调用成员函数
std::vector<MyType> vec;
// populate...
auto m = std::max_element(std::begin(vec), std::end(vec),
[](const MyType& a, const MyType& b) { return a.val() < b.val()})
并按对象的val()
s对对象进行排序。我忽略了stdlib的某个部分,它能帮助我解决这个问题吗?还是另一种简单的方法?我想让这是什么排序或搜索尽可能明显
我知道仅仅
&MyType::val
是不够的,我正在寻找一种可以包装它的东西,或者提供类似的功能而不模糊其含义的东西。一旦重载操作符你可以使用std::mem\fn
(或者std::tr1::mem\fn
)
请参见模板比较器可以帮助您:
template <typename StructureType,
typename MemberType,
MemberType StructureType::*member>
bool comparator(const StructureType& the_first, const StructureType& the_second)
{
return the_first.*member < the_second.*member;
}
模板
布尔比较器(const-StructureType&第一个,const-StructureType&第二个)
{
返回第一个.*成员<第二个.*成员;
}
一点类型特征魔法当然可以让您避免编写类型。您可以通过引入任何新函数(模板化或非模板化)来做到这一点
使用bind
和std::less
auto m = std::max_element(vec.begin(), vec.end(),
bind(less<>(), bind(&MyType::val, _1), bind(&MyType::val, _2)));
auto m=std::max_元素(vec.begin(),vec.end(),
绑定(less(),绑定(&MyType::val,_1),绑定(&MyType::val,_2));
为避免使用std::mem\u fn
而对sehes答案进行的改进是为compare\u by
函数提供一个指向成员重载的指针
示例用法
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field));
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field, std::greater<>{}));
std::sort(std::begin(vec)、std::end(vec)、compare_by(&MyType::field));
std::sort(std::begin(vec),std::end(vec),compare_by(&MyType::field,std::greater{}));
要实现的代码
#include <functional> // std::less
#include <utility> // std::move
#include <type_traits> // std::is_invocable_r
// Forward declaration
template<typename R, typename T, typename F = std::less<R>>
auto compare_by(R T::*, F = F{});
// Implementation
namespace detail {
template<typename T, typename F>
struct compare_by_t;
template<typename R, typename T, typename F>
struct compare_by_t<R T::*, F> : private F
{
compare_by_t(F&& f, R T::*m): F{std::move(f)}, _member{m} {}
R T::* _member;
bool operator()(T const& x, T const& y) const
{
return F::operator()(x .* _member, y .* _member);
}
};
} // detail
template<typename R, typename T, typename F>
auto compare_by(R T::* member, F f)
{
static_assert(std::is_invocable_r<bool, F, R, R>::value);
return detail::compare_by_t<R T::*, F>{ std::move(f), member };
}
#包含//标准::更少
#include//std::move
#include//std::是否可开票
//远期申报
模板
自动比较(rt::*,F=F{});
//实施
名称空间详细信息{
模板
按t进行结构比较;
模板
结构比较\u by\u t:private F
{
用{std::move(F)},{m}成员{m}比较
R T::*\U成员;
布尔运算符()(T常量和x,T常量和y)常量
{
返回F::operator()(x.*.\u成员,y.*.\u成员);
}
};
}//细节
模板
自动比较依据(R T::*成员,F)
{
静态断言(std::is\u invocable\u r::value);
返回detail::compare_by_t{std::move(f),member};
}
因为说某事物比另一事物小往往没有意义。如果我想按工资对员工进行分类,那就意味着要重载操作符,而我想lambda是你能期望的最短的可能性。当然,你也可以用std::bind
和std::less
进行叠加,但这将更难理解,imo。好吧,这是一个有价值的选择,但是(@Ryan)请告诉我为什么这应该比一行lambda更好?它的意思是这样的(我在阅读你的建议之前已经纠正了它)。。。我在这里问他,我猜他是选民中的一员。“当然,我只是停留在上下文中,考虑不使用LAMBDAS为前提。我也会使用一个,除非我有std::算法在使用诸如less
/greater
/greater\u equal
等操作之间交替使用,并且std::
使我的生活更轻松。在这里转发是毫无意义的。一次移动并不会比什么都不做增加任何效率,而这正是当你只是通过引用传递时所得到的。此版本的C++11之前版本中没有副本。为什么要添加移动呢?在库代码中尽可能完美地向前移动可能是一个“好”习惯。但在可能的情况下,思考自己在做什么可能是一个“更好”的习惯。其中less
是一个C++1y功能。@dyp在VS2013中工作,使其less
在g++4.8中工作。是的,这是MSVC支持的“提前”功能之一,如make_unique
。IIRC都是我的微软员工提出的。很好。我喜欢std::bind
。然而,在这种情况下,lambda显然是优越的(这仍然重复相同的部分)。此外,功能组合的嵌套绑定可能会非常笨拙和令人惊讶(,)+但是,1表示信息丰富。注:我想不需要val()
成员
auto m = std::max_element(vec.begin(), vec.end(),
bind(less<>(), bind(&MyType::val, _1), bind(&MyType::val, _2)));
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field));
std::sort(std::begin(vec), std::end(vec), compare_by(&MyType::field, std::greater<>{}));
#include <functional> // std::less
#include <utility> // std::move
#include <type_traits> // std::is_invocable_r
// Forward declaration
template<typename R, typename T, typename F = std::less<R>>
auto compare_by(R T::*, F = F{});
// Implementation
namespace detail {
template<typename T, typename F>
struct compare_by_t;
template<typename R, typename T, typename F>
struct compare_by_t<R T::*, F> : private F
{
compare_by_t(F&& f, R T::*m): F{std::move(f)}, _member{m} {}
R T::* _member;
bool operator()(T const& x, T const& y) const
{
return F::operator()(x .* _member, y .* _member);
}
};
} // detail
template<typename R, typename T, typename F>
auto compare_by(R T::* member, F f)
{
static_assert(std::is_invocable_r<bool, F, R, R>::value);
return detail::compare_by_t<R T::*, F>{ std::move(f), member };
}