Hello Everybody,
Most of my coding experience is in C. Although I have a background in C++, I know very little of STL and the advanced topics in C++.
I came across this code

struct g
{
	g():n(0)
    {
    }
	int operator()() { return n++; }
	int n;
};

int main()
{
	int a[10];
	std::generate(a, a+10, g());
	std::copy(a, a+10, std::ostream_iterator<int>(std::cout, " "));
	getch();
	return 0;
}

The output that I get is 0 1 2 3 4 5 6 7 8 9
Now this is my under standing of what is happening. The generate function calls the function g(). This function first assign n the value of 0
What I am unable to understand is how and where is the overloaded () operator called ? And how does it get called 10 times when the function g() is just called once.

Edited 6 Years Ago by abhimanipal: n/a

Hello Everybody,

int operator()() { return n++; }

yikes this is not a good idea to call a function without a name I don't think I have ever wanted to overwrite the operator() this is overloading a constructor in a class, change the name or use operator++ Generate although I haven't used it clearly calls g() several times. I guess it populates a using g()

Your code seems to use some very odd/scary choices what is it supposed to be doing?

if you are learning C++ use a class not a struct

if you need a unique number in a constructor there are better ways to do this.

if you are asking about g() your choice of line 14 seems to be unwise. Use code that has a clear intention or comment it. Although, it might seem the best solution now you will end up using different containers.

I missed that this was code that you were not intending to use but although in some ways it is clean code stay well away from it

it is using () to turn a struct into a class
rather than using a global or a static it does the silly n++ better would have been but still not my choice

/*fill a with the numbers 0-9*/
#include <iostream>
#include <vector>
int main()
{
int sz(10);
int a[sz];

//fill a using an int
//param three needs to be function pointer or ()
int i(0);
//i have not tested i++ as a function that is allowed
std::generate(a, a+10, i++); 
/*
going from first to last of a 
calling ++i;
*/

/* a for loop would be a minimal overhead and a better choice for now
*/

std::vector<int> vb;
vb.reserve(sz);
for(int j(0); j < sz; ++j)
{
vb.push_back(j);
}

//line 14 does the same as this
for(int k(0); k< sz ; ++k)
{
std::cout << vb[k] <<  " ";
}

//iterators would be faster



return 0;
}

I am sorry but this is an interview question. I do not plan to use it anywhere..:)
This code calls the function just once. I used a cout statement to check this
How exactly is the overloaded () operator being called or where is it being called from ?

Edited 6 Years Ago by abhimanipal: n/a

Both of the previous responses to this question were incorrect. The code snippet you see here is perfectly valid and is an idiom oft used by the STL. The struct g represents a function object, or functor. It overloads the function call operator, that is its purpose. What this means is that g() represents a call of the overloaded operator() not a call to the constructor.

You can sort of consider a function object to be a normal function written in a more complicated way. instead of writing all the function statements in the body of the function -

void foo()
{
   [I]statements[/I]
}

you can write them in the body of the operator() of the function object class...

class FunctionObjectTye
{
public:
   void operator() ()
   {
      [I]statements[/I]
   }
};

There are certain advantages to this approach when considering the STL.

1. a function object may be considered smarted as it can maintain state. So for instance you can have multiple instances of a function object which can have sifferent states at the same time. this is not possible with normal functions.
2. Each function object has its own type. Therefore you can pass a function object type to a template as a parameter to specify certain behaviour, and you have the advantage that container tyupes with different function objects differ.
3. A function object is usually faster than a functio pointer.

I can't explain it all here cos it isquite a large subject but yu should do a google for more information on this.

I missed that this was code that you were not intending to use but although in some ways it is clean code stay well away from it

it is using () to turn a struct into a class
rather than using a global or a static it does the silly n++ In C++ the only difference between a class and a struct is the default protection level. struct default to public while classes default to private. So

struct foo
{
   int i;
};

is essentially equivalent to

class foo
{
public:
   int i;
};

Ok lets get another -1

The point that I was making about the () is that its use makes the
code difficult to read, while not taking into account the operations that the computer has to perform.

It is half measure that does not make syntatic sense without knowing it is a special case

class foo
{
public:
 foo();
//operator() looks like a function called operator
 int operator() () {return 0;}
 std::string name;
}

how do you call this...

#include "foo.h"

int main()
{
foo * f = new foo();
int i = f->operator()();
foo f1;
int i = f1();
return 0;
}

Brackets should not follow operator precidence as they are a special symbol meaning do what is inside me first.
While when f1 is close to its declaration its purpose is clear if this is in real code

int i = f1();
//why not 
double d = f2();

there is no obvious connection between f1 and its class.
what is its real world meaning supposed to be.

There is no indication of purpose in the variable name!

While at first glance std::generate is a function that looks useful
the two example functions
of
1 - filling an array with incremental values
or
2 - rand(); are fundamentally different to use a function pointer and a specific function would seem clearest as what in effect is being done is casting the variable in example 1.

2 - this case is interesting for what is actually being done is a psudo-random array is being copied into another array but using a function call is masking the behaviour - but it has a clear intention so the loss of overhead is worth it.

example 1 is not the most efficient logic to create an array with incremental values and second function for this would exist
called generate incremental something like

template <class T>
void generate_incremental(T * begin, T * end, T start_value)
{
   while(begin != end)
   {
      *begin = start_value++;
      ++begin;
   }
}

whereas generate logically has

*begin = function();

so has the logical overhead of a function call which presumably the compiler will clean up.

The power of stl is that it is optimised code that is widely used but it should not override making your code and intentions clear.

if

struct foo1
{
int i;
int operator() () {return i;}
}

then

foo1 f1;
f1.i = foo1();//this is valid..

this is behaviour that makes foo1 look like a class to the eye

if you are going to acccept code like this why not use asm...

Just because something can be done does not mean this is the way it should be done.

As the OP stated in one of his posts this is an interview question. The example is contrived and should not be rated for efficiency etc. The purpose of the code snippet is to determine knowledge of the declaration and usage of function objects.

I stated the reasoning behind their usage and provided a link to a great deal of information on their purpose.

If the OP goes into his interview and tries to talk his way around the syntax as you have done above all he will do is demonstrate his lack of knowledge on the subject.

I haven't voted down your posts out of a desire to embarass you or to appear better than you but simply because the information you provided was wrong. Incorrect help is worse than no help at all.

Overloading of the function call operator is a perfecly valid use of the language. An important feature which allow us to write code that takes nontrivial operations as parameters, such as the generic algorithms provided by the STL.

Another quick thing, the name of the object in the example is not well chosen for a real world problem, it has been chosen to obfuscate the purpose of the code, in this case to make sure that when the interviewee answers that they actually know what they are talking about. In the real world typically you would name your function object after the operation it carries out e.g. Add, Divide, etc..

Edited 6 Years Ago by mattjbond: spelling

This will be my final post on this thread you'll be glad to hear.

my previous post probably shows a character flaw
but it had not been stated that it was an interview question in the original post and I assumed that this was a sample of how to populate an array from a book and this is what was the purpose of the original question.

while my explanation in both posts might have deserved a -1, I strongly felt that I had to clarify my reasoning. And I have been in interviews where a piece of C code is used for a discussion as C++ and the interviewers expected criticism of the code.

The variation of the code I found was the example:
http://www.cplusplus.com/reference/algorithm/generate/

where the function pointer at least makes the distinction between a constructor and operator() in the call to the UniqueNumber but it masks its behaviour with the g() in the example.

The operator() in essence is trying to emulate the behivour of std::vector constructor and overloading the return type means that the same written code can mean different things in different places.

It exists as a transition between struct and classes but has long since passed its necessity. Yes its behaviour is defined to the compiler but its logic is a work around when there is no need to use its implementation and it will not run faster.

As the OP stated in one of his posts this is an interview question.

It exists as a transition between struct and classes but has long since passed its necessity. Yes its behaviour is defined to the compiler but its logic is a work around when there is no need to use its implementation and it will not run faster.

I'm afraid that I don't understand that.

This article has been dead for over six months. Start a new discussion instead.