簡體   English   中英

我應該為比較函子擴展std :: less嗎?

[英]Should I extend std::less for a comparison functor?

我想創建一個shared_ptr內容比較函子來代替關聯容器和std算法中的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 ,就像我正在擴展已棄用的std::binary_function 在C ++ 03中,我實際上通過std::less擴展它。 但是,當std::binary_function被刪除時,這也可以從C ++ 03移植到C ++ std::binary_function甚至是C ++ 17,因為它只是跟隨std::less的變化。

我已經在StackOverflow上閱讀了一些關於std::less use,自定義比較函子,甚至一些標准規范和提議的答案。 我看到std::less和指導擴展STL容器,但我似乎找不到任何擴展std::less或指導它的例子。 我錯過了不這樣做的明顯理由嗎?

編輯:刪除了C ++ 11標記,因為它引起了回答者的混淆。 我希望能夠實現前向可移植性,但需要C ++ 03。 如果您提供其他人使用的C ++ 11答案(完全沒問題),請注意。

當你在你的問題說,如果你繼承std::less的,你會得到三個類型定義是在std::less 我最喜歡繼承它的是它描述了你的意圖。 當我看見

struct some_non_specific_name : std::less<some_type>

我知道這是一個函數,它將表現為< for some_type 我沒有必要閱讀結構體來找出任何東西。

據我所知,你不會錯過任何劣勢。 如您所述,您將自動獲取typedef 必須在兩種情況下定義operator< ,並且其實現沒有差異。

有一件事你可能會發現你可能會發現整潔,糟糕或者只是不適用於你的用例(來自這里這里 ):有一個std::less for std::less<void>的專門化,它有一個模板operator<為給定的參數推斷operator<的返回類型operator<

除非您打算使用SharedPtrContentsLess<void> (這可能完全沒有意義),否則兩種解決方案都是等效的。

我寫了一個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做一個*然后調用myless

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和< s)。

您可以通過簡單地將調用轉發給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> {};

因為std :: less缺少虛擬析構函數(即僅隱式析構函數),所以繼承它可能在技術上導致未定義的行為 由於兩種類型都不包含任何數據成員,因此無論對象如何被引用,銷毀都應該有效,但是標准禁止通過靜態析構函數進行多態刪除,因為在大多數情況下它存在很大的問題(切片,不完全刪除)。

看到這個答案: 你不能繼承std :: vector

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM