Sign in to follow this  
setiz1

operator( )

Recommended Posts

Hi folks While going through sample shared_ptr example in Boost tutorial, I encountered a code such as one below:
struct Foo
{ 
  Foo( int _x ) : x(_x) {}
  
  ~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; }
  
  int x;

  
};

typedef boost::shared_ptr<Foo> FooPtr;

struct FooPtrOps
{
  bool operator()( const FooPtr & a, const FooPtr & b )
  { return a->x > b->x; } // 1 (see below)
  
  void operator()( const FooPtr & a )
  { std::cout << a->x << "\t";} // 2 (see below)
};


The FooPtrOps is then used in main as such:
int main()
{
  std::vector<FooPtr>         foo_vector;
  std::set<FooPtr,FooPtrOps>  foo_set; 
  ....
  // I then added some code to insert values
  for(int i = 0; i < 100; i++)
  {
	  FooPtr tmpNewPtr(new Foo(i));	
	  foo_vector.push_back(tmpNewPtr);
	  foo_set.insert(tmpNewPtr);
  }

  // Print 'em
  std::cout << "foo_vector:\n";
  std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );
  
  std::cout << "\nfoo_set:\n"; 
  std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() );
  std::cout << "\n";

  return 0;
}

So my question is: How is the functor FooPtrOps( ) managing to print using the 1 & 2 above? Particularly using the "operator()" function? I thought that it instead should have had been defined such:
friend ostream& operator<<(ostream& os_out, const FooPtr& foo_out)
{
 os_out << foo_out->x << "\t";
}

because, it defines what "<<" means for a type FooPtr. Right? Any help is appreciated. Thanks! [Edited by - setiz1 on September 11, 2009 2:08:13 AM]

Share this post


Link to post
Share on other sites
Uhmm.. I think after staring at the code in the post I made earlier, I found the answer myself (the trick is to relax and drink some water ;-):

For FooPtrOps() in the for_each, operator() is called every time FooPtrOps() is called.
So, in accordance with the above statement, if I had operator<< function defined in FooPtrOps struct, calling FooPtrOps<< should work right?

Thanks!

Share this post


Link to post
Share on other sites
struct FooPtrOps
{
void operator()( const FooPtr & a )
{ std::cout << a->x << "\t";} // 2 (see below)
};

std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );


Inside the for_each "FooPtrOps()" is constructing a temporary FooPtrOps object. It's the same as writing:
FooPtrOps temp;
std::for_each( foo_vector.begin(), foo_vector.end(), temp );


Then, for_each calls temp.operator()( x ) for each element in the vector (where x is the current element).

Share this post


Link to post
Share on other sites
Quote:
Original post by Hodgman
*** Source Snippet Removed ***

Inside the for_each "FooPtrOps()" is constructing a temporary FooPtrOps object. It's the same as writing:*** Source Snippet Removed ***

Then, for_each calls temp.operator()( x ) for each element in the vector (where x is the current element).


Yep I got that bit too.. Thanks Hodgman:) But what about this?


bool operator()( const FooPtr & a, const FooPtr & b )
{ return a->x > b->x; }



Why is it comparing the two values and returning it? Is it mandatory to have this comparator?
If I comment this function out, I get a compile-time error:

1>c:\program files\microsoft visual studio 9.0\vc\include\xutility(313) : error C2064: term does not evaluate to a function taking 2 arguments
1> class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
1> c:\program files\microsoft visual studio 9.0\vc\include\xtree(637) : see reference to function template instantiation 'bool std::_Debug_lt_pred&lt;_Pr,_Kty,boost::shared_ptr&lt;T&gt;&gt;(_Pr,const _Ty1 &,const _Ty2 &,const wchar_t *,unsigned int)' being compiled
1> with
1> [
1> _Pr=FooPtrOps,
1> _Kty=FooPtr,
1> T=Foo,
1> _Ty1=FooPtr,
1> _Ty2=boost::shared_ptr&lt;Foo&gt;
1> ]



Why so? Thanks.

[Edited by - setiz1 on September 11, 2009 2:25:28 AM]

Share this post


Link to post
Share on other sites
The way you've written the code it's a bit confusing. The FooPtrOps class is being used for two different things.

The first thing is, as we've already seen, this: void operator()(const FooPtr &) is being using in the call to std::for_each to print out the value of x.

But the other use is where you are passing FooPtrOpts as the second template parameter to std::set. In this case, std::set uses bool operator(const FooPtr &, const FooPtr &) to order the FooPtr's inside the set.

In general, it's probably not a good idea to use the one class for two totally different things like that, because it'll only lead to confusion :-)

Share this post


Link to post
Share on other sites
Notice how the set is declared. That's important.
Hint: Look at the definition of the set template.

Answer:
The second template parameter to a set is a functor which performs comparison between two elements to determine their relationship. It does this by calling that functor on the elements of the set during insertion and other operations as needed.

Since the equivalence relationship of set is a strict relationship (that is you don't have "less than or equal to", or similarly "greater than or equal to") one can test if x and y are equal by testing if both compare(x, y) == compare(y, x) == false. Since if x and y are equal and you are using say the std::less functor then you end up with: less(x, y) /* which is false */ == less(y, x) /* which is also false */ == false;. Note that since the relationship is strict, you do not have to test for false since the only case where compare(x, y) == compare(y, x) is in the case of x == y.

Share this post


Link to post
Share on other sites
Ahh.. the std::set is using it internally to compare the 2 values. damn how did I miss it :-/

Thanks Codeka and Washu! :-)

Indeed Codeka I agree with you, I haven't been worrying too much about the structure of the code since my intention is to learn the intricacies of Boost and C++ as fast as possible (I do Python during the day) but by night I am a C++ programmer but only so much as time permits. Need to rest too. I am only a human :-(

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this