Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

operator (), what is it?

102 views
Skip to first unread message

Doug Mika

unread,
Apr 13, 2015, 1:35:33 PM4/13/15
to
Hi to all, I was wondering what overloading the operator() is?
I know that overloading an operator< allows for the direct comparison of my two objects using <, but what about the operator(), especially in a struct? Does it allow the struct to be called like a function?

// list::remove_if
#include <iostream>
#include <list>

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }

// a predicate implemented as a class:
struct is_odd {
bool operator() (const int& value) { return (value%2)==1; }
};

int main ()
{
int myints[]= {15,36,7,17,20,39,4,1};
std::list<int> mylist (myints,myints+8); // 15 36 7 17 20 39 4 1

mylist.remove_if (single_digit); // 15 36 17 20 39

mylist.remove_if (is_odd()); // 36 20

std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

return 0;
}

thanx

Victor Bazarov

unread,
Apr 13, 2015, 2:58:26 PM4/13/15
to
On 4/13/2015 1:35 PM, Doug Mika wrote:
> Hi to all, I was wondering what overloading the operator() is?

It's called "operator function call". What book are you reading that
does not explain it?

> I know that overloading an operator< allows for the direct
> comparison
of my two objects using <, but what about the operator(), especially in
a struct? Does it allow the struct to be called like a function?
>
> // list::remove_if
> #include <iostream>
> #include <list>
>
> // a predicate implemented as a function:
> bool single_digit (const int& value) { return (value<10); }
>
> // a predicate implemented as a class:
> struct is_odd {
> bool operator() (const int& value) { return (value%2)==1; }
> };
>
> int main ()
> {
> int myints[]= {15,36,7,17,20,39,4,1};
> std::list<int> mylist (myints,myints+8); // 15 36 7 17 20 39 4 1
>
> mylist.remove_if (single_digit); // 15 36 17 20 39
>
> mylist.remove_if (is_odd()); // 36 20

That's a call to the template function 'remove_if' and providing a
temporary object as its argument. You need to understand what
'remove_if' does in order to comprehend this fully. Step into it using
your debugger, and take a good look at the code.

>
> std::cout << "mylist contains:";
> for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
> std::cout << ' ' << *it;
> std::cout << '\n';
>
> return 0;
> }

Predicates designed to work with standard functions like 'for_each',
'copy_if', etc., need to provide a special member function - the
operator function call, with a particular argument number and types.

Get yourself a decent book on C++ and read it. Daily.

V
--
I do not respond to top-posted replies, please don't ask

Richard

unread,
Apr 14, 2015, 4:14:24 PM4/14/15
to
[Please do not mail me a copy of your followup]

Doug Mika <doug...@gmail.com> spake the secret code
<ea2187b1-aced-4be3...@googlegroups.com> thusly:

>Hi to all, I was wondering what overloading the operator() is?
>I know that overloading an operator< allows for the direct comparison of
>my two objects using <, but what about the operator(), especially in a
>struct? Does it allow the struct to be called like a function?

The standard library often has algorithms that take predicates as
arguments. For instance, std::list::remove_if takes a UnaryPredicate
argument <http://en.cppreference.com/w/cpp/container/list/remove>:

"template <class UnaryPredicate>
void remove_if(UnaryPredicate p);

Removes all elements satisfying specific criteria [...]
removes all elements for which predicate p returns true."

The argument p is a model of UnaryPredicate, a function that can be
called like:

bool pred(int a);

for a std::list<int>. You can supply a predicate function in many
ways, such as:

1) a pointer to a function

bool is_odd(int a) { return (a % 2) == 1; }
// ...
mylist.remove_if(is_odd);

2) a lambda function

my_list.remove_if([](int a) { return (a % 2) == 1; });

3) a function object

struct is_odd {
bool operator()(int a) { return (a % 2) == 1; }
};
my_list.remove_if(is_odd());

4) some other expression for which 'pred(a)' is well defined and
returns a bool:

bool remainder_is_one(int b, int a) { return (a % b) == 1; }
my_list.remove_if(std::bind(remainder_is_one, 2));

One of the reasons for introducing lambdas into the language was to
simplify the use of such "function objects", particularly when they
are simple expressions such as "is this an odd integer".

In your example code, the predicate passed to remove_if was an
anonymous instance of the struct is_odd that overrode the function
call operator with a single argument. (In my examples, I wrote the
argument declaration as 'int a', instead of 'const int &a', since it
isn't useful to pass integers by const reference.)

> mylist.remove_if (single_digit); // 15 36 17 20 39

This uses a pointer to the function single_digit.

> mylist.remove_if (is_odd()); // 36 20

This uses an anonymous (unnamed) instance of the struct is_odd.

Remember also that the primary difference between struct and class is
that class has private visibility by default and struct has public
visibility by default. Anything you can do with a class you can also
do with a struct.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Robbie Hatley

unread,
Apr 24, 2015, 7:58:25 AM4/24/15
to

On 4/13/2015 10:35 AM, Doug Mika wrote:

> Hi to all, I was wondering what overloading the operator() is?

That's called an "application operator". If you define one for
a struct or class, that struct or class can then function as
a "functor" (function-like class). If you instantiate an object
of the class, you can then use that object as if it was a function.

Compile and run the following to see what I mean:


#include <iostream>
struct SayHi
{
void operator() (void)
{
std::cout << "Hello, World!" << std::endl;
}
};
int main (void)
{
SayHi Greeter;
Greeter();
return 0;
}


--
Cheers,
Robbie Hatley
Midway City, CA, USA
perl -le 'print "\154o\156e\167o\154f\100w\145ll\56c\157m"'
http://www.well.com/user/lonewolf/
https://www.facebook.com/robbie.hatley

Victor Bazarov

unread,
Apr 24, 2015, 8:06:27 AM4/24/15
to
On 4/24/2015 7:58 AM, Robbie Hatley wrote:
>
> On 4/13/2015 10:35 AM, Doug Mika wrote:
>
>> Hi to all, I was wondering what overloading the operator() is?
>
> That's called an "application operator". If you define one for
> a struct or class, that struct or class can then function as
> a "functor" (function-like class). If you instantiate an object
> of the class, you can then use that object as if it was a function.
>
> Compile and run the following to see what I mean:
>
>
> #include <iostream>
> struct SayHi
> {
> void operator() (void)
> {
> std::cout << "Hello, World!" << std::endl;
> }
> };
> int main (void)
> {
> SayHi Greeter;
> Greeter();
> return 0;
> }

To the OP:

Also note, that if the op() function does not change the object for
which it is called, it's better to declare it 'const':

void operator()() const

. Also, refrain from putting 'void' where nothing is needed (I mean the
argument list). It's easier to read and understand. If nothing is
supposed to be there, nothing needs to be declared there. Having 'void'
to designate an empty argument list is a C-ism.

BTW, another way of achieving the same effect would be to instantiate
and use the object in the same expression. The 'main' function in
Robbie's example might therefore be rewritten as

int main()
{
SayHi()();

Richard

unread,
Apr 28, 2015, 3:47:05 PM4/28/15
to
[Please do not mail me a copy of your followup]

Victor Bazarov <v.ba...@comcast.invalid> spake the secret code
<mhdbhr$om9$1...@dont-email.me> thusly:

>On 4/24/2015 7:58 AM, Robbie Hatley wrote:

>> #include <iostream>
>> struct SayHi
>> {
>> void operator() (void)
>> {
>> std::cout << "Hello, World!" << std::endl;
>> }
>> };
>> int main (void)
>> {
>> SayHi Greeter;
>> Greeter();
>> return 0;
>> }
>
>. Also, refrain from putting 'void' where nothing is needed (I mean the
>argument list). It's easier to read and understand. If nothing is
>supposed to be there, nothing needs to be declared there. Having 'void'
>to designate an empty argument list is a C-ism.

FYI, I've got a change in review to add a check to clang-tidy that
will replace (void) argument lists with (), so you can kill off this
C-ism from your code base in an automated and reliable way :-)

<http://reviews.llvm.org/D7639>

Scott Lurndal

unread,
Apr 28, 2015, 4:42:02 PM4/28/15
to
legaliz...@mail.xmission.com (Richard) writes:
>[Please do not mail me a copy of your followup]
>
>Victor Bazarov <v.ba...@comcast.invalid> spake the secret code
><mhdbhr$om9$1...@dont-email.me> thusly:
>
>>On 4/24/2015 7:58 AM, Robbie Hatley wrote:
>
>>> #include <iostream>
>>> struct SayHi
>>> {
>>> void operator() (void)
>>> {
>>> std::cout << "Hello, World!" << std::endl;
>>> }
>>> };
>>> int main (void)
>>> {
>>> SayHi Greeter;
>>> Greeter();
>>> return 0;
>>> }
>>
>>. Also, refrain from putting 'void' where nothing is needed (I mean the
>>argument list). It's easier to read and understand. If nothing is
>>supposed to be there, nothing needs to be declared there. Having 'void'
>>to designate an empty argument list is a C-ism.
>
>FYI, I've got a change in review to add a check to clang-tidy that
>will replace (void) argument lists with (), so you can kill off this
>C-ism from your code base in an automated and reliable way :-)

So you don't like it. That doesn't make it wrong. In fact, IMO
it is better to have int function(void) { do_something; }.

>
><http://reviews.llvm.org/D7639>

Hope it's optional.

IIRC, using void that way was introduced with C++, not with C.

Victor Bazarov

unread,
Apr 28, 2015, 4:53:58 PM4/28/15
to
On 4/28/2015 4:41 PM, Scott Lurndal wrote:
> legaliz...@mail.xmission.com (Richard) writes:
>> [Please do not mail me a copy of your followup]
>>
>> Victor Bazarov <v.ba...@comcast.invalid> spake the secret code
>> <mhdbhr$om9$1...@dont-email.me> thusly:
>>
>>> On 4/24/2015 7:58 AM, Robbie Hatley wrote:
>>
>>>> #include <iostream>
>>>> struct SayHi
>>>> {
>>>> void operator() (void)
>>>> {
>>>> std::cout << "Hello, World!" << std::endl;
>>>> }
>>>> };
>>>> int main (void)
>>>> {
>>>> SayHi Greeter;
>>>> Greeter();
>>>> return 0;
>>>> }
>>>
>>> . Also, refrain from putting 'void' where nothing is needed (I mean the
>>> argument list). It's easier to read and understand. If nothing is
>>> supposed to be there, nothing needs to be declared there. Having 'void'
>>> to designate an empty argument list is a C-ism.
>>
>> FYI, I've got a change in review to add a check to clang-tidy that
>> will replace (void) argument lists with (), so you can kill off this
>> C-ism from your code base in an automated and reliable way :-)
>
> So you don't like it. That doesn't make it wrong. In fact, IMO

"In fact"? So, it's a fact that such is your opinion? Good one!

> it is better to have int function(void) { do_something; }.
>
>>
>> <http://reviews.llvm.org/D7639>
>
> Hope it's optional.
>
> IIRC, using void that way was introduced with C++, not with C.

YRI

Richard

unread,
Apr 28, 2015, 5:41:07 PM4/28/15
to
[Please do not mail me a copy of your followup]

sl...@pacbell.net spake the secret code
<jgS%w.483011$IH4....@fx08.iad> thusly:

>legaliz...@mail.xmission.com (Richard) writes:
>>[Please do not mail me a copy of your followup]
>>
>>Victor Bazarov <v.ba...@comcast.invalid> spake the secret code
>><mhdbhr$om9$1...@dont-email.me> thusly:
>>
>>>On 4/24/2015 7:58 AM, Robbie Hatley wrote:
>>
>>>> #include <iostream>
>>>> struct SayHi
>>>> {
>>>> void operator() (void)
>>>> {
>>>> std::cout << "Hello, World!" << std::endl;
>>>> }
>>>> };
>>>> int main (void)
>>>> {
>>>> SayHi Greeter;
>>>> Greeter();
>>>> return 0;
>>>> }
>>>
>>>. Also, refrain from putting 'void' where nothing is needed (I mean the
>>>argument list). It's easier to read and understand. If nothing is
>>>supposed to be there, nothing needs to be declared there. Having 'void'
>>>to designate an empty argument list is a C-ism.
>>
>>FYI, I've got a change in review to add a check to clang-tidy that
>>will replace (void) argument lists with (), so you can kill off this
>>C-ism from your code base in an automated and reliable way :-)
>
>So you don't like it. That doesn't make it wrong.

It's clutter. It needlessly increases cognitive load when reading code.

>><http://reviews.llvm.org/D7639>
>
>Hope it's optional.

If you want to leave that clutter in your code, nothing is making you
remove it.

>IIRC, using void that way was introduced with C++, not with C.

C++ had function overloading and always had type signatures and
therefore writing

int foo(void);

is just a more verbose and cluttered way of writing

int foo();

It was introduced into C when function prototypes were added. Prior to
function prototypes, writing:

int foo();

Declared a function named foo, with an unspecified number of arguments
of unspecified types, returning an int.

The only way to properly declare a function taking no arguments in C
is to write:

int foo(void);

The *only* place where writing (void) is important is C. That's why
it's a C-ism.

Bjarne Stroustrup recommends that you simply write 'int foo()' and I
do too. My addition to clang-tidy turns that advice into an automated
robot that can clean up that clutter in your code base all the time
without you having to do it in an error-prone manual way.

If you like hoarding unnecessary tokens in your code, then by all
means, keep them.
0 new messages