Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Function Objects

Posted on 2004-08-20
6
240 Views
Last Modified: 2013-12-14

In my quest to understand function objects, portions of the code below is a mystery to me.  So now:

# include <iostream>
# include <ostream>
# include <string>
# include <sstream>
# include <vector>
# include <algorithm>

struct Split
 {
  std::string Buffer;
  std::vector<unsigned char> Vec;

  Split( std::string Src ) : Buffer( Src )
   {
    std::istringstream Iss( Buffer );

    while( Iss.good() && std::getline( Iss, Buffer, '.' ) )
           Vec.push_back( std::strtoul( Buffer.c_str(), 0, 10 ) );
   }

  void operator() ( char ) const {}

  operator std::vector<unsigned char>() const { return Vec; }
 };

int main()
 {
  std::string Src( "1.3.6.1.5.1.11.3.2.1.4.25.0" );

  std::vector<unsigned char> Vec =
       std::for_each( Src.begin(), Src.end(), Split( Src ) );

  std::copy( Vec.begin(), Vec.end(),
             std::ostream_iterator<int>( std::cout, "\n" ) );

  return 0;
 }

I understand the basic premise behind the call to for_each, which involves calling Split for each Src element from begin to end (or one past end).  Debuging the code shows a different story.

First the constuctor for Split gets called.  getline removes the token '.' and the object now contains 13 elements.

operator() (char)  gets called twenty seven (27) times.  I know because I placed  a static counter within operator().  This was a mystery to me, but then I discovered that each element within Src is treated as such.  A char.  So when operator() (char) gets called twice for '11' etc.

The confusion  stems from the fact that the code within the constructor  - as I understand it - has partitioned the Src object and placed the result in Vec.  What's the net gain for calling Split 27 times.  In essence operator() (char) isn't doing much or am I mistaken?

Consider:
  operator () (char)
  operator std::vector<unsigned char>() const { return Vec; }

The primary (used sparingly) difference between the two function objects is the latter specifies the return type while the former does not?  The latter is needed for visibility into Vec contained in Split?

Thanks in advance
0
Comment
Question by:forums_mp
  • 2
  • 2
  • 2
6 Comments
 
LVL 19

Assisted Solution

by:drichards
drichards earned 20 total points
ID: 11852795
>> I understand the basic premise behind the call to for_each, which involves calling Split for each Src element from begin to end >> (or one past end).  Debuging the code shows a different story
No, you have misunderstood how the for_each works.  It calls the function for each element of Src from Src.begin() to Src.end().  For a string, the iterator goes one character at a time, so for each character in Src (there are 27 characters) 'operator()(char)' is called.

The end result is that the for_each calls the NO-OP operator a bunch of times.  You would achieve the same result with:

   std::string Src( "1.3.6.1.5.1.11.3.2.1.4.25.0" );
   std::vector<unsigned char> Vec = Split(Src);
   std::copy( Vec.begin(), Vec.end(),std::ostream_iterator<int>( std::cout, "\n" ) );

The really important part of your for_each is to construct the Split struct.  The iteration of for_each chews up some CPU cycles but doesn't accomplish anything.

And you do not have two function objects.  One function object with a cast operator and the 'function' operator.
0
 

Author Comment

by:forums_mp
ID: 11853922

So all the 'works' was been done the first time via the call to Split constructor.  Right?

I assume by NO-OP operator you mean operator () (char)?  I realize operator () (char) is doing nothing which I suspect constitues NO-OP, well......

I might add that I've not see anything about function operator in Jousittis but what makes this
  operator char*() { return "test" ; }
a function operator?

IOW, I interpret the above to mean.  An 'unnamed' function returning a char*.  The addition of the operator keyword adds a new 'dimension' but I'm unsure what.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11855145
>> So all the 'works' was been done the first time via the call to Split constructor.  Right?
Exactly.  Merely constructing the object performs the split into the vector.

A function object (in this context) is nothing more that an object that implements an operator() with appropriate parameters.  In for_each, the parameter list needs to be a single parameter of whatever type the iterator dereferences to.  In your case it is char, so you provide 'operator() (char)'.

>>  The addition of the operator keyword adds a new 'dimension' but I'm unsure what.
An operator is not unnamed as you could call an operator as 'a.operator+(b)' rather than saying 'a+b' if you really wanted.  The difference is that operators may be called implicitly.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
LVL 15

Expert Comment

by:efn
ID: 11857357
>> what makes this
>>  operator char*() { return "test" ; }
>>a function operator?

It's not a function operator, it's a conversion operator.  A function call operator is operator() (possibly with some parameters), so you could declare a function call operator that returns char* like this:

char* operator();

--efn
0
 

Author Comment

by:forums_mp
ID: 11877072

Here's I suspect one last question/example on this.  For some reason I still struggle with the function object syntax.  Consider

# include <iostream>
# include <ostream>

template<class NumT> struct limit_range
 {
  NumT Value;
  NumT MinValue;
  NumT MaxValue;

  explicit limit_range( NumT value, NumT Tmin, NumT Tmax )
           : Value( value ), MinValue( Tmin ), MaxValue( Tmax ) {}

    operator int() const
     {
      return  ( Value >= MinValue ) && ( Value <= MaxValue ) ?
                Value :
                throw std::runtime_error( "Value is out of range.\n" );
     }
 };

class SomeObject
 {
  private:
     int N;
  public:
     SomeObject( int n ) : N( limit_range<int>( n, 100, 200 ) ) {}

     void SetValue( int n ) { N = limit_range<int>( n, 100, 200 ); }
 };

int main()
 {
  try
   {
    SomeObject A( 150 );
    SomeObject B( 200 );

    B.SetValue( 201 );
   }
  catch( const std::runtime_error& e )
   {
    std::cerr << "ERROR: " << e.what() << std::endl;
   }

  return 0;
 }

How does the compiler transform the constructor call  "limit_range<int>( n, 100, 200 )" into operator int().
I'm thinking.  The constructor gets called and now I'm left with N().  However, N is not of type limit_range so how does the operator int() gets called?
0
 
LVL 15

Accepted Solution

by:
efn earned 30 total points
ID: 11877401
limit_range<int>( n, 100, 200 )

is not really a constructor call, it tells the compiler to construct a temporary limit_range object.  In general, if a class C has a default constructor, you can code C() to specify a temporary object of that class, and if it has a constructor with parameters, you can pass parameters in the parentheses.

So

 N( limit_range<int>( n, 100, 200 ) )

initializes the int N with the temporary limit_range object.  The compiler knows N is an int, so it expects an int to initialize it.  The limit_range object is not an int, but it has a conversion operator that converts to int, so the compiler automatically converts the limit_range to an int and uses the int to initialize N.  The general principle is that if you use an object of class C in a context that calls for an object of another type D, and C has a conversion operator that converts a C to a D, the compiler will automatically use the conversion operator.

There is no function object anywhere in this example.  For a type T,

T operator()

declares a function call operator that returns a T, while

operator T()

declares a conversion operator that converts to T.

--efn
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question