【问题标题】:Overloaded operators for std::bind placeholdersstd::bind 占位符的重载运算符
【发布时间】:2012-07-06 01:23:51
【问题描述】:

boost::bind 为其占位符重载了几个运算符:

为方便起见,bind 产生的函数对象重载了逻辑非运算符 ! 以及关系和逻辑运算符 ==!=<<=>、@987654329 @、&&||

例如,这允许我将_1 == desired_value 作为谓词传递给 STL 算法。

不幸的是,std::bind 似乎没有重载这些运算符:(

  1. 这是为什么呢?

  2. std::bind 模拟_1 == desired_value 有什么好的解决方法?

【问题讨论】:

  • 我认为这是因为 C++11 有 lambda,因此我不明白你为什么需要这样的运算符。 (这条评论似乎是一个答案)。
  • @Nawaz std::bind 是 TR1 的一部分,比 C++11 早了 6 年。
  • Fred,但是现在它是std::的一部分,而不是tr1::
  • 您始终可以创建自己的占位符,并为这些占位符重载运算符

标签: c++ boost stl operator-overloading bind


【解决方案1】:

std::bind 似乎没有重载这些运算符? 这是为什么呢?

因为 C++11 添加了 lambda,它提供了相同的甚至更好的便利来生成匿名函子对象。

用 std::bind 模拟 _1 == desired_value 的好方法是什么?

std::bind 不用于模拟行为。使用 C++11 lambda 实现您问题的答案:

std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), [](int i) -> bool { return i == desired_value; });

请注意,如果您使用的是可以派生返回类型的相当新的编译器,则不需要“-> bool”语法。

如果您不想或不能使用 C++11 lambda,那么您可以像这样创建一个非匿名仿函数:

bool IsDesiredValue (int i) {
    return (i == desired_value);
}
std::vector<int>::iterator i = std::find_if (myvector.begin(), myvector.end(), IsDesiredValue);

再举一个例子,这里是使用 C++11 lambdas 来创建匿名函子,以按类型的值对向量进行排序:

std::sort(myVector.begin(), myVector.end(), [](const Foo& i, const Foo& j) -> bool { return i.myValue < j.myValue; });

另一种非 lambda 版本是:

struct myclass {
  bool operator() (const Foo& i, const Foo& j) { return (i.myValue < j.myValue); }
} myobject;
std::sort(myVector.begin(), myVector.end(), myobject);

以下是使用 boost 的运算符重载进行相同排序的方法:

std::sort(myVector.begin(), myVector.end(), boost::bind(&MyClass::myValue, _1) < boost::bind(&MyClass::myValue, _2))

【讨论】:

    【解决方案2】:

    您始终可以自己为占位符重载这些运算符,例如operator&lt;

    struct less12
    {
        template<typename T, typename U>
        bool operator()(const T& a, const U& b) const
        {
            return a < b;
        }
    };
    
    less12 operator<(decltype(_1), decltype(_2))
    {
        return less12();
    }
    
    
    struct less21
    {
        template<typename U, typename T>
        bool operator()(const U& b, const T& a) const
        {
            return a < b;
        }
    };
    
    less21 operator<(decltype(_2), decltype(_1))
    {
        return less21();
    }
    
    
    template<typename T>
    struct lessa1
    {
        const T& a;
    
        template<typename U>
        bool operator()(const U& b) const
        {
            return a < b;
        }
    };
    
    template<typename T>
    lessa1<T> operator<(const T& a, decltype(_1))
    {
        lessa1<T> result = {a};
        return result;
    }
    
    
    template<typename U>
    struct less1b
    {
        const U& b;
    
        template<typename T>
        bool operator()(const T& a) const
        {
            return a < b;
        }
    };
    
    template<typename U>
    less1b<U> operator<(decltype(_1), const U& b)
    {
        less1b<U> result = {b};
        return result;
    }
    

    这是一个使用示例,与活页夹(自定义 less12std::less)和 lambda 语法相比:

    template<typename Iterator>
    void quicksort(Iterator begin, Iterator end)
    {
        // ...
        auto m = std::partition(begin + 1, end, _1 < *begin);
    
        auto m = std::partition(begin + 1, end, std::bind(less12(), _1, *begin));
    
        auto m = std::partition(begin + 1, end, std::bind(std::less<typename std::iterator_traits<Iterator>::value_type>(), _1, *begin));
    
        auto m = std::partition(begin + 1, end, [begin](const typename std::iterator_traits<Iterator>::value_type& x) { return x < *begin; } );
        // ...
    }
    

    真的很期待N3421 和这里的多态 lambda :)

    【讨论】:

      【解决方案3】:

      IIRC,Boost.Bind 仅重载了占位符的那些运算符,因为 Boost.Bind 是对原始 Boost Lambda 库的改进(由于 Boost.Phoenix,Boost.Bind 已过时,顺便说一句)。 std::bind 的占位符仅用于该目的,作为 std::bind 的参数的占位符。

      作为一种解决方法,使用多态函子:

      struct compare_equal{
        template<class LHS, class RHS>
        bool operator()(LHS&& lhs, RHS&& rhs){ // assume bool return
          return std::forward<LHS>(lhs) == std::forward<RHS>(rhs);
        }
      };
      
      // ...
      auto bound = std::bind(compare_equal(), _1, desired_value);
      

      Live example on Ideone.

      【讨论】:

      • @Nawaz:您刚刚说明了我试图在您的 cmets 中告诉您的确切问题。我没有在我的代码中使用任何特定类型,使其完全通用。 lambda 需要您准确说明将使用的类型。
      • @Xeo c++1y lambdas 不这样做吗?就个人而言,我比 c++11 lambdas 更喜欢 Boost Phoenix。它们通常更短,更容易阅读,垃圾语法更少。
      【解决方案4】:

      我认为这是因为 C++11 有 lambda,因此我不明白你为什么需要这样的运算符。

      【讨论】:

      • 没有多态的 lambdas 使它仍然有用。
      • _1 推断参数类型,而您需要为 lambdas 显式指定它。
      • @Xeo:我还是没看懂。你要说的是_1 和 C++11 lambda 的工作方式不同。但问题是,他们实现的不是一样的吗?
      • 如果你可以[](auto arg){ ... },他们会的,但你不能。
      • 是的,你可以自己写类型,但是如果你打算在泛型代码中使用它,那就失败了。您不能使用通用 lambda,但 boost::bind 的占位符在设计上是通用的。
      猜你喜欢
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 1970-01-01
      • 2020-03-12
      • 2018-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多