C ++ 11 - 绑定排序函数

时间:2013-12-12 17:19:57

标签: c++ c++11

我想节省一些打字,因此定义如下:

using namespace std;

vector<MyClass> vec;

auto vecsort = bind(sort, vec.begin(), vec.end(), [] (MyClass const &a, MyClass const &b) {
        // custom comparison function
    });

vecsort(); // I want to use vecsort() a lot afterwards

由于某些原因,这不能编译 - 为什么?

使用提升不是一种选择。

最小的工作示例:

#include <vector>
#include <utility>
#include <algorithm>
#include <functional>

using namespace std;

int main() {

    vector<pair<int, int>> vec;
    for (int i = 0; i < 10; i++)
        vec.push_back(make_pair(10 - i, 0));

    auto vecsort = bind(sort, vec.begin(), vec.end(), [] (pair<int, int> const &a, pair<int, int> const &b) {
            return a.first < b.first;
        });

    vecsort();

}

错误:

  

error: no matching function for call to 'bind(<unresolved overloaded function type>, std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, main()::__lambda0)'

3 个答案:

答案 0 :(得分:12)

问题是std::sort不是函数对象。它是一个功能模板。处理该问题的最简单方法是创建一个简单的包装器对象:

struct sorter {
    template <typename RndIt, typename Cmp>
    void operator()(RndIt begin, RndIt end, Cmp cmp) {
        std::sort(begin, end, cmp);
    }
};

现在你可以使用

std::bind(sorter(), vec.begin(), vec.end(), [](...){ ... });

答案 1 :(得分:7)

其他人已经提到过为什么它不能编译,但是这个备用解决方案对你有用吗?这使用另一个lambda而不是bind来创建std :: function。

#include <vector>
#include <utility>
#include <algorithm>
#include <functional>
#include <iostream>

using namespace std;

int main() {

    vector<pair<int, int>> vec;
    for (int i = 0; i < 10; i++) {
        vec.push_back(make_pair(10 - i, 0));
    }

     auto vecsort = [&vec] {
        sort(vec.begin(), vec.end(), 
        [] (pair<int, int> const &a, pair<int, int> const &b) {
            return a.first < b.first;
        });
     };

    // vecsort will work as long as vec is in scope.
    // vecsort will modify the original vector.
    vecsort();
    for (auto i : vec) {
        std::cout << '(' << i.first << ", " << i.second << ") ";
    }
    std::cout << endl;

    vec.push_back(make_pair(-42, 0));
    vecsort();
    for (auto i : vec) {
        std::cout << '(' << i.first << ", " << i.second << ") ";
    }
    std::cout << endl;
}

输出:

(1, 0) (2, 0) (3, 0) (4, 0) (5, 0) (6, 0) (7, 0) (8, 0) (9, 0) (10, 0)
(-42, 0) (1, 0) (2, 0) (3, 0) (4, 0) (5, 0) (6, 0) (7, 0) (8, 0) (9, 0) (10, 0)

看到它在这里运行: http://ideone.com/W2YQKW

答案 2 :(得分:3)

这是一个有用的宏来解决这个问题。它的作用是创建一个匿名struct,其实例表示在特定上下文中调用特定函数名(通过字符串值)的重载集。

C ++遗憾地缺乏这样的功能。如果只有人会向C ++标准化委员会提出建议。唉。 1

#define OVERLOAD_SET(FUNCTION_NAME) struct { template<typename... Args>\
  auto operator()(Args&&... args) const->\
    decltype(FUNCTION_NAME(std::forward<Args>(args)...))\
  {  return (FUNCTION_NAME(std::forward<Args>(args)...));  } \
}

在全球范围内:

OVERLOAD_SET( std::sort ) sorter;

然后,在使用时:

std::bind( sorter, vec.begin(), vec.end(), [](...) {...} );

问题是std::sort是一个template(或者可能是一组通过重载选择的template!),它们在被调用时生成函数,而不是实际函数。它看起来像一个函数,但事实并非如此。并且template和过载集不能直接传递给其他函数。

顺便说一下,可以通过添加OVERLOAD_SET来改进上面的template<typename R, typename... Args> operator R(*)(Args...)() const宏,这允许OVERLOAD_SET隐式地转换为特定的函数指针,但这是超出了这个问题的范围。


1 Xeo提出了这样的建议。