operator( )

Started by
5 comments, last by setiz1 14 years, 7 months ago
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]
Advertisement
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!
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).
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 arguments1>        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 arguments1>        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 compiled1>        with1>        [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]
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 :-)
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.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

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 :-(

This topic is closed to new replies.

Advertisement