我想在关联容器和std算法中创建一个shared_ptr内容比较函子来代替std::less<T>
。我已经看到了几个使用以下(或类似)模型的自定义比较器的例子:
template <typename T>
struct SharedPtrContentsLess {
bool operator()(const boost::shared_ptr<T>& lhs,
const boost::shared_ptr<T> rhs) const {
return std::less<T>(*lhs, *rhs);
//or: return (*lhs) < (*rhs);
}
//defining these here instead of using std::binary_functor (C++11 deprecated)
typedef boost::shared_ptr<T> first_argument_type;
typedef boost::shared_ptr<T> second_argument_type;
typedef bool return_type;
};
但为什么我不想延伸std::less
?像这样:
template <typename T>
struct SharedPtrContentsLess : public std::less< boost:shared_ptr<T> > {
bool operator()(const boost::shared_ptr<T>& lhs,
const boost::shared_ptr<T> rhs) const {
return std::less<T>(*lhs, *rhs);
}
};
这会给我带来任何东西吗?
我认为这会免费获得typedef
s,好像我正在扩展已弃用的std::binary_function
。在C ++ 03中,我实际上将扩展到std::less
。但是,当std::binary_function
被移除时,这也可以从C ++ 03移植到C ++ 11/14甚至是C ++ 17,因为它只是跟随std::less
中的更改。
我在StackOverflow上阅读了一些关于std::less
使用,自定义比较函子,甚至一些标准规范和提案的答案。我看到std::less
的特化和 的指南来扩展STL容器,但我似乎无法找到任何扩展std::less
的示例或针对它的指导。我错过了不这样做的明显理由吗?
编辑:删除了C ++ 11标签,因为它引起了回答者的混淆。我希望能够实现前向可移植性,但需要C ++ 03。如果您提供其他人使用的C ++ 11答案(完全没问题),请注意。
答案 0 :(得分:1)
正如你在问题中所说的那样,如果你继承自std::less
,那么你将获得std::less
中的三个typedef。我最喜欢继承它的是它描述了你的意图。当我看到
struct some_non_specific_name : std::less<some_type>
我知道这是一个仿函数,对于<
来说就像some_type
一样。我没有必要阅读结构体来找出任何东西。
答案 1 :(得分:1)
据我所知,你不会错过任何劣势。如您所述,您将自动获得typedef
s。必须在两种情况下定义operator<
,并且其实现没有区别。
有一件事你可能会发现你可能会发现整洁,糟糕或者不适用于你的用例(来自here和here):std::less
有一个专业化对于具有模板std::less<void>
的{{1}},推导出给定参数的operator<
的返回类型。
除非您打算使用operator<
(可能根本没有意义),否则两种解决方案都是等效的。
答案 2 :(得分:1)
我写了deref_less
。首先,my_less
聪明地调用std::less
:
struct my_less {
template<class Lhs, class Rhs,
class R = std::result_of_t< std::less<>( Lhs const&, Rhs const& ) >
// class R = decltype( std::declval<Lhs const&>() < std::declval<Rhs const&>() )
>
R operator()(Lhs const&lhs, Rhs const&rhs)const{
return std::less<>{}(lhs, rhs); // or lhs<rhs
}
// exact same type uses `std::less<T>`:
template<class T,
class R = std::result_of_t< std::less<>( T const&, T const& ) >
>
R operator()(T const& lhs, T const& rhs)const{
return std::less<T>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t< std::is_base_of<Lhs, Rhs>{} && !std::is_same<Lhs, Rhs>{} >* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const{
return std::less<Lhs const*>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t< std::is_base_of<Rhs, Lhs>{} && !std::is_same<Lhs, Rhs>{} >* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const{
return std::less<Rhs const*>{}(lhs, rhs);
}
template<class Lhs, class Rhs,
std::enable_if_t<
!std::is_base_of<Rhs, Lhs>{}
&& !std::is_base_of<Lhs, Rhs>{}
&& !std::is_same<Lhs, Rhs>{}
>* = nullptr
>
bool operator()(Lhs const* lhs, Rhs const* rhs)const = delete;
};
然后,执行deref_less
的{{1}}会调用*
:
myless
在C ++ 14中,但我使用的所有内容都很容易替换(例如,struct deref_less {
template<class Lhs, class Rhs,
class R = std::result_of_t< my_less( decltype(*std::declval<Lhs>()), decltype(*std::declval<Rhs>()) ) >
>
R operator()(Lhs const& lhs, Rhs const&rhs)const {
return my_less{}( *lhs, *rhs );
}
};
可以替换为decltype和std::less<>
。
答案 3 :(得分:1)
您可以通过简单地将调用转发给std :: less或任何其他类似对象,为任何可解除引用的对象(即任何(智能)指针)创建可重用的模板。
// c++11
template<template<class> Op, class T> struct deref_mixin;
template<template<class> Op, class T>
struct deref_mixin {
auto operator()(const T &l, const T &r) const
-> decltype(std::declval<Op<T>>()(*l, *r)) {
return Op<T>{}(*l, *r);
}
};
template<template<class> Op>
struct deref_mixin<Op, void> {
template<class T, class U>
auto operator()(const T &l, const U &r) const
-> decltype(std::declval<Op<T>>()(*l, *r)) {
return Op<void>{}(*l, *r);
}
};
template<class T> using less_deref = deref_mixin<std::less, T>;
template<class T> using greater_deref = deref_mixin<std::greater, T>;
template<class T> using my_comparator_deref = deref_mixin<my_comparator, T>;
// c++03
template<template<class> Op, class T>
struct deref_mixin {
bool operator()(const T &l, const T &r) const {
Op<T> op;
return op(*l, *r);
}
};
// Technically, the void template partial specialization isn't defined in c++03, but it should have been :)
template<template<class> Op>
struct deref_mixin<Op, void> {
template<class T, class U>
bool operator()(const T &l, const U &r) const {
Op<void> op;
return op(*l, *r);
}
};
template<class T> struct less_deref : deref_mixin<std::less, T> {};
答案 4 :(得分:0)
由于std :: less缺少虚拟析构函数(仅隐式析构函数),因此从技术上继承可能会导致未定义行为。由于这两种类型均不包含任何数据成员,因此无论引用对象如何,销毁均应有效,但是该标准禁止通过静态析构函数进行多态删除,因为在大多数情况下,它极有可能出现问题(切片,不完全删除)。