Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我应该为比较函子扩展std::less吗?_C++_Stl_C++03 - Fatal编程技术网

C++ 我应该为比较函子扩展std::less吗?

C++ 我应该为比较函子扩展std::less吗?,c++,stl,c++03,C++,Stl,C++03,我想在关联容器和std算法中创建一个共享的内容比较functor来代替std::less。我见过几个使用以下(或类似)模型的自定义比较器示例: 这能给我买点什么吗 我想这会让我免费获得typedefs,就好像我在扩展不推荐的std::binary_函数。在C++03中,我实际上是通过std::less扩展它。然而,当std::binary_函数被删除时,它也可以从C++03移植到C++11/14,甚至C++17,因为它只是跟随std::less中的更改 我已经阅读了大量关于StackOverfl

我想在关联容器和std算法中创建一个共享的内容比较functor来代替
std::less
。我见过几个使用以下(或类似)模型的自定义比较器示例:

这能给我买点什么吗

我想这会让我免费获得
typedef
s,就好像我在扩展不推荐的
std::binary_函数
。在C++03中,我实际上是通过
std::less
扩展它。然而,当
std::binary_函数
被删除时,它也可以从C++03移植到C++11/14,甚至C++17,因为它只是跟随
std::less
中的更改

我已经阅读了大量关于StackOverflow的答案,这些答案涉及
std::less
使用、自定义比较函数,甚至一些标准规范和建议。我看到了
std::less
的专门化和不扩展STL容器的指导,但我似乎找不到任何扩展
std::less
的例子或反对它的指导。我是否错过了一个明显的不这样做的理由


编辑:删除了C++11标记,因为它会给回答者带来混乱。我希望提高可移植性,但C++03是必需的。如果您只提供一个C++11答案供其他人使用(完全可以),请注意。

正如您在问题中所说,如果您从
std::less
继承,您将得到
std::less
中的三个typedef。我最喜欢从它继承的是它描述了你的意图。当我看到

struct some_non_specific_name : std::less<some_type>
struct一些非特定的名称:std::less

我知道这是一个函子,在我看来,它的行为就像一个
,你不会错过任何缺点。正如您所提到的,您将自动获得
typedef
s。
操作符我会写一个
deref\u 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;
};
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 );
  }
};

在C++14中,我使用的所有东西都很容易替换(
std::less
可以用decltype替换,
您可以通过简单地将调用转发到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> {};
/c++11
模板结构deref_mixin;
模板
混合结构{
自动运算符()(常数T&l,常数T&r)常数
->decltype(std::declval()(*l,*r)){
返回Op{}(*l,*r);
}
};
模板
混合结构{
模板
自动运算符()(常数T&l、常数U&r)常数
->decltype(std::declval()(*l,*r)){
返回Op{}(*l,*r);
}
};
使用较少的deref=deref\u mixin的模板;
使用更大的\u deref=deref\u mixin的模板;
使用my_comparator_deref=deref_mixin的模板;
//c++03
模板
混合结构{
布尔运算符()(常数T&l,常数T&r)常数{
Op;
返回op(*l,*r);
}
};
//从技术上讲,c++03中没有定义void模板部分专门化,但它应该是:)
模板
混合结构{
模板
布尔运算符()(常数T&l,常数U&r)常数{
Op;
返回op(*l,*r);
}
};
模板结构less_deref:deref_mixin{};

因为std::less缺少虚拟析构函数(即仅隐式析构函数),从中继承可能会在技术上导致未定义的行为。由于这两种类型都不包含任何数据成员,因此无论对象如何引用,销毁都应该有效,但标准禁止通过静态析构函数进行多态删除,因为在大多数情况下,多态删除极有可能出现问题(切片、不完全删除)

看看这个答案:

您的代码是否真的要在C++03编译器中编译?这是否值得做额外的工作?@Yakk:是的,目前我们使用的是gcc4.4.7,它对C++11的支持非常有限。我们希望进行更新,但有一些复杂的原因我们还没有这样做,包括安全自我认证要求和支持程序,这些程序目前仍使用较旧的编译器。不过,这里的额外工作是什么?第一个版本也是C++11版本的样子,不是吗?@Yakk:我想我现在明白你的意思了。我不认为第二个版本是更多的工作在所有。事实上,看起来工作量更少,意图更明确,这正是我们在代码中所渴望的(即优雅)。当然,它看起来像是更少的代码和更为通用的C++(在我看来)。如果您认为第一个版本在两个标准中都更可取是有原因的,请详细说明。毕竟,这就是我要问的!更少的工作也不是:根本不做任何typedef,也不继承。请注意,继承有一个小问题,因为切片可能会发生。在
SharedPtrContentsLess
std::less
之间。我还不完全理解这个答案,但顶部的所有内容(
my_less
)是否都是为了解决我的两个版本中的切片问题?在C++03中有解决这个问题的好方法吗?@BloodGain不是切片,而是
是的,我添加了C++11标记,因为我希望这是向前移植的。我现在看到它引入了太多的混乱,所以我删除了它。上下文中的问题是关于前向可移植性的,所以这就足够了。谢谢@如果您同时需要C++11和C++03,我会包括这两个标记。如果你只需要一个,就只包含一个。我刚刚注意到在其中一条评论中,你对C++11代码的访问是有限的。您可以摆脱返回类型的确定,只使用bool。这应该满足任何谓词用例。我决定将这个答案标记为已接受,因为它显示了一个更好的通用方法来实现我想要做的事情。我认为这个问题的实际答案在雅克的一个评论中(切片的危险)。如果有人决定对此进行扩展,我会将其标记为问题的最直接答案,但我认为这和雅克的答案提供了最好的指导。这是一个C++03版本
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 );
  }
};
// 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> {};