如何使用boost :: bind为std :: set定义排序标准

时间:2012-03-20 21:26:32

标签: c++ boost stl

我想我在设定的术语上遗漏了一些东西。

以下代码适用于对矢量进行排序:

using boost::bind;
std::vector<SegPoly> result;
//...
std::sort(result.begin(),result.end(),bind(std::less<double>(),bind(&SegPoly::getLength,_1), bind(&SegPoly::getLength,_2)));

但我不能对std::set

使用这样的排序标准
 using boost::bind;
  std::set<SegPoly> polySet(inPolys.begin(),inPolys.end(),bind(std::less<double>(),bind(&SegPoly::getLength,_1), bind(&SegPoly::getLength,_2)));

这会产生超出我能力范围的神秘编译错误:

没有用于调用'std :: set,std :: allocator&gt; :: set(__ gnu_cxx :: __ normal_iterator&gt;&gt;,__ gn_cxx :: __ normal_iterator&gt;&gt;,boost :: _ bi :: bind_t的匹配函数,boost :: _ bi :: list2,boost :: _ bi :: list1&gt;&gt;,boost :: _ bi :: bind_t,boost :: _ bi :: list1&gt;&gt;&gt;&gt;)'

任何人都知道这个错误在哪里?

7 个答案:

答案 0 :(得分:2)

没有错误。您需要在创建std::set时指定比较函数/仿函数,它是类型的一部分。现在,boost::bind的类型未指定,因为根据参数,它可以创建多种类型。

解决方案可能是使用boost::function

typedef std::set<SegPoly, boost::function<bool(unsigned, unsigned)> > set_type;
set_type s(inPolys.begin(), inPolys.end(),
    boost::bind(std::less<double>(),boost::bind(&SegPoly::getLength,_1), boost::bind(&SegPoly::getLength,_2)));

更好,更有效的选择是创建自己的比较器:

struct SegPolyComp{
  bool operator()(SegPoly const& lhs, SegPoly const& rhs) const{
    return lhs.getLength() < rhs.getLength();
  }
}

std::set<SegPoly, SegPolyComp> s(inSegPoly.begin(), inSegPoly.end());

答案 1 :(得分:2)

如前所述(现在多次),您需要将比较器对象的类型作为模板参数传递,然后将该类型的实例作为参数传递。试图用Boost绑定做这件事......丑陋,IMO。如果你有C ++ 11可用,你可能会考虑使用lambda:

auto pred = [](SegPoly const &left, SegPoly const &right) { 
    return left.getLength() < right.getLength(); 
};

std::set<SegPoly, decltype(pred)> 
    polySet(inPolys.begin(),inPolys.end(), pred);

答案 2 :(得分:1)

bind返回一个函数,这是你需要进行严格弱排序所需的静态类型。

typedef std::set<foo, boost::function<bool(const foo &, const foo &)> > foos_t;

然后您可以使用bind在运行时设置该功能。这是一个完整的例子。

TEST(strict_weak) {
    struct foo {
        int a;
        int b;
        static bool with_a(const foo &lhs, const foo &rhs) {
            return lhs.a < rhs.a;
        }
        static bool with_b(const foo &lhs, const foo &rhs) {
            return lhs.b < rhs.b;
        }
    };
    typedef std::set<foo, boost::function<bool(const foo &, const foo &)> > foos_t;
    {{ // scope
        foos_t foos(boost::bind(foo::with_a, _1, _2));
        foo p; p.a = 4; p.b = 1;
        foo q; q.a = 2; q.b = 5;
        foos.insert(p);
        foos.insert(q);
        for (const foo &e : foos)
            cout << "with_a " << e.a << ", " << e.b << endl;
    }}
    {{ // scope
        foos_t foos(boost::bind(foo::with_b, _1, _2));
        foo p; p.a = 4; p.b = 1;
        foo q; q.a = 2; q.b = 5;
        foos.insert(p);
        foos.insert(q);
        for (const foo &e : foos)
            cout << "with_b " << e.a << ", " << e.b << endl;
  }}
}

输出:

with_a 2, 5
with_a 4, 1
with_b 4, 1
with_b 2, 5

答案 3 :(得分:0)

比较器是集合类型的一部分。你不能只传递任何东西作为第二个参数。如果要传递bind的结果,您可能希望将比较器设为function<bool (T,T)>,然后在构造期间传递活页夹。

我从未真正做过,所以我不能告诉你更多。祝你好运:)

从错误消息开始,它告诉你在你的集合中,没有构造函数将bind的结果作为比较器参数。

答案 4 :(得分:0)

std::set被声明为template < class Key, class Compare = less<Key>, class Allocator = allocator<Key> > class set。通过编写std::set<SegPoly>,您迫使set使用默认比较器std::less<SegPoly>,而不是您定制的比较器。您已将整个类型的boost monstrosity作为模板参数传递给std::set

答案 5 :(得分:0)

std::set不是序列容器;相反,它是一个 associative 容器。排序仅对序列容器有意义,其中元素以某种固定顺序(即添加它们的顺序)出现。

但是,您可能很高兴地知道,迭代std::set可以保证按照您在定义集合类型时指定的顺序访问元素的递增顺序(默认为{ {1}})。您不能在集迭代中传递任何其他顺序。但是,您可以在创建集类型时提供自己的比较函子;只要知道比较通过“相等”来定义集合的含义。

答案 6 :(得分:0)

你不能像这样构造std :: set,因为你需要指定Comparator functor类型作为模板参数,除了函子本身作为构造函数arg。