2010-09-08 59 views
2

例如,我想写过载功能set_difference该类型std::set<point>如何为STL容器和算法函数编写重载操作符?

class myIter : public std::iterator<std::input_iterator_tag, int> { 
public: 
    myIter(int n) : num(n){} 
    myIter(const myIter & n) : num(n.num){} 
    int & operator *(){return num;} 
    myIter & operator ++(){++num; return *this;} 
    bool operator !=(const myIter & n){return n.num != num;} 
private: 
    int num; 
}; 

struct point 
{ 
    point(int X, int Y):x(X), y(Y){} 
    int x; 
    int y; 
} 

int main() 
{ 
    set <point> myset; 
    myset.insert(point(1, 1); 
    myset.insert(point(3, 2); 
    myset.insert(point(5, 3); 

    //find the missing elements in set for `point.x` using `set_difference` 

    std::set<int> missing; 

    std::set_difference(myIter(myset.begin()->x+1), myIter(myset.rbegin()->x), 
    myset.begin(), myset.end(), std::insert_iterator<std::set<int>>(missing, missing.begin())); 

} 

比较应用std::set_differencepoint.x变量后,set<int> missing必须是:

missing[0] {2} 
missing[1] {4} 

我怎么知道怎么写操作的重载操作符?

回答

3

首先,std::set<point>要求point是低于可比。您可以为point定义operator<,或者提供一个单独的函数对象,将比较结果作为第二个模板参数std::set<point,MyCompare>

一旦你真的拥有了你的元素,你可以使用set_difference。值得注意的是,set_difference实际上并不要求您使用std::set作为输入---您只需使用矢量,从而避免必须提供比较功能。

要使用set_difference,你需要确保value_type S中的2个迭代器范围是一样的,所以你需要另一个迭代器的包装,只返回第二范围x部分point值。

std::set_difference(myIter(myset.begin()->x+1), myIter(myset.rbegin()->x), 
    extractXIter(myset.begin()), extractXIter(myset.end()), 
    std::insert_iterator<std::set<int>>(missing, missing.begin())); 
0

IIUC,你是你的类型实现operator<()后,因为它使用的几种类型和标准库的算法:

struct point 
{ 
    point(int X, int Y):x(X), y(Y){} 
    int x; 
    int y; 
}; 

inline bool operator<(const point& lhs, const point& rhs) 
{ 
    if(lhs.x < rhs.x) return true; 
    if(lhs.x > rhs.x) return false; 
    return lhs.y < rhs.y; 
} 

这是判断的一个相当简单的方式这点是“小”。您可能想要改进算法,但语法机制保持不变。


需要注意的是,一旦你定义p1 < p2,你的类型的用户通常更希望p1 > p2(和p1 <= p2等)正常工作。由于这是微不足道的,它不会伤害提供比较操作符的其余部分:

inline bool operator> (const point& lhs, const point& rhs) {return rhs < lhs;} 
inline bool operator<=(const point& lhs, const point& rhs) {return !(lhs > rhs);} 
inline bool operator>=(const point& lhs, const point& rhs) {return !(lhs < rhs);} 
inline bool operator==(const point& lhs, const point& rhs) 
{ 
    return lhs.x < rhs.x && lhs.y == rhs.y; 
} 
inline bool operator!=(const point& lhs, const point& rhs) {return !(lhs==rhs);} 
+0

的使用注意事项Boost.Operators'的'无缝地定义这些“completary运营商”自动:) – 2010-09-08 07:35:26

+0

@Matthieu:我一直在指望你出现和建议那。 ':)'(我现在还没有机会在一年内做很多C++,所以我从来没有试过这个,我不自觉地提出我自己没有做过的事情,也不知道如何去做所以随时都可以随时指出它的出处) – sbi 2010-09-08 07:38:43

+0

我很高兴:)它的语法糖更避免写任何“功能性”的样板代码,但它有助于保持代码整洁。 – 2010-09-08 08:10:02

1

(在回答我的第二次尝试。)

这是相当安东尼·威廉姆斯的回答的阐述。

您需要的两个迭代器都可以在Boost库中使用(您自己的myIter缺少可能使您的代码无法与其他编译器一起编译的功能)。

#include <set> 
#include <algorithm> 
#include <iostream> 
#include <boost/iterator/counting_iterator.hpp> 
#include <boost/iterator/transform_iterator.hpp> 
#include <boost/mem_fn.hpp> 

struct point 
{ 
    point(int X, int Y):x(X), y(Y){} 
    int x; 
    int y; 
}; 

bool operator< (const point& a, const point& b) 
{ 
    return a.x < b.x || (a.x == b.x && a.y < b.y); 
} 

int main() 
{ 
    std::set <point> myset; 
    myset.insert(point(1, 1)); 
    myset.insert(point(3, 2)); 
    myset.insert(point(5, 3)); 

    //find the missing elements in set for `point.x` using `set_difference` 
    std::set<int> missing; 
    using namespace boost; 
    std::set_difference(
    counting_iterator<int>(myset.begin()->x+1), counting_iterator<int>(myset.rbegin()->x), 
    make_transform_iterator(myset.begin(), mem_fn(&point::x)), 
    make_transform_iterator(myset.end(), mem_fn(&point::x)), 
    std::inserter(missing, missing.begin())); 
    std::copy(missing.begin(), missing.end(), std::ostream_iterator<int>(std::cout, " ")); 
} 

问题的兴趣:

  • point需求是 “小于” 相媲美,如果你想将它们存储在set
  • boost::counting_iterator是一个更好的myIter
  • boost::transform_iterator允许您在解除引用时将值应用于该值。结合boost::mem_fn,当迭代器被解除引用时,它将获得Point::x成员。
  • 使用助手功能std::inserter得到推断
  • 结果不必存储在模板参数在set(同样没有输入必须来自一个set,只要在范围相对于分类。所使用的断言 - 在这里比较X会员