C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Why prohibit static operator()()?
Goto page 1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Tom
Guest





PostPosted: Tue Dec 30, 2003 12:28 pm    Post subject: Why prohibit static operator()()? Reply with quote



Two questions:

1. Why does the standard not permit a functor to use a static
overload of operator()()?

2. Does the implicit "this" pointer passed by the nonstatic
operator()() get optimized away in a typical implementation?

Consider, for example, the typical implementation of the Standard
Library's std::less functor:

template<class T>
struct less : public binary_function<T, T, bool>
{
bool operator()(const T& t1, const T& t2) const
{
return t1 < t2;
}
};

std::less takes two arguments t1 and t2 and returns the result of
operator<(t1, t2). Since operator()() is nonstatic, though, in
addition to passing const references to t1 and t2, a const pointer to
this is also passed. std::less has no class members, though, and
therefore no state, so no information is conveyed by passing the this
pointer. All (or almost all – perhaps I've overlooked one) of the
Standard Library's functors defined in stateless and therefore pass a wasted pointer. So why does the
standard prohibit a static overload of operator()()?

I looked at prior newsgroup discussion of this issue, and the
responses fell into two categories: (1) people who responded, in
essence, "why would you ever have a stateless functor?", apparently
overlooking the Standard Library's wide use of stateless functors in
algorithms and associative containers; and (2) people who responded
that permitting static overloads of operator()() would either increase
the complexity of, or break entirely, name look-up rules. Is the
latter really true?

Which brings me to my second question: In a typical implementation,
is the extra pointer simply optimized away on an optimized build? One
reason the Standard Library uses functor templates instead of function
templates to pass to algorithms and associative containers is that a
functor is more readily inlined than the call via the function pointer
that the algorithm would otherwise be passed. Assuming that the
functor call is in fact inlined, is the passing of the this pointer
typically optimized away, so that this apparent loss of efficiency is
really a non-issue?

Best regards,

Tom

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
James Kanze
Guest





PostPosted: Tue Dec 30, 2003 7:56 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote



[email]Thomas8675309 (AT) yahoo (DOT) com[/email] (Tom) writes:

Quote:
Two questions:

1. Why does the standard not permit a functor to use a static
overload of operator()()?

What would it mean? A () operator requires a left operand.

Quote:
2. Does the implicit "this" pointer passed by the nonstatic
operator()() get optimized away in a typical implementation?

I suspect that most implementations don't bother, because it would make
no measurable difference. A pointer to the object is floating around in
a register somewhere anyway.

Quote:
Consider, for example, the typical implementation of the Standard
Library's std::less functor:

template struct less : public binary_function {
bool operator()(const T& t1, const T& t2) const
{
return t1 < t2;
}
};

In this case, the function is inline, so I would imagine that the
reference to the object gets eliminated even before the call. This is a
typical example of where inlining will win more than just the removal of
a function call.

Quote:
std::less takes two arguments t1 and t2 and returns the result of
operator<(t1, t2). Since operator()() is nonstatic, though, in
addition to passing const references to t1 and t2, a const pointer
to this is also passed.

The function is inline. It is also fairly trivial. A compiler which
didn't generate it inline when optimization is active is seriously
defectuous, IMHA. And of course, if the function is generated inline,
there is no issue of passing parameters.

[...]

Quote:
One reason the Standard Library uses functor templates instead of
function templates to pass to algorithms and associative containers
is that a functor is more readily inlined than the call via the
function pointer that the algorithm would otherwise be passed.

With which compiler? Constant propagation is one of the oldest
optimization techniques known -- it would be a very poor compiler which
would still generate an indirect function call if the pointer to a
function were a constant.

I think the reason why the library uses functional objects rather than
functions is more fundamental -- how on earth could it define the
typedef's for first_argument_type, second_argument_type and result_type
if it used a pointer to a function?

Quote:
Assuming that the functor call is in fact inlined, is the passing of
the this pointer typically optimized away, so that this apparent
loss of efficiency is really a non-issue?

Given that all of the functions involved are inline, it would be a very
poor compiler where this made a difference.

--
James Kanze mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ron Natalie
Guest





PostPosted: Tue Dec 30, 2003 8:29 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote




"Tom" <Thomas8675309 (AT) yahoo (DOT) com> wrote

Quote:
Two questions:

1. Why does the standard not permit a functor to use a static
overload of operator()()?

Because operators that are defined with member functions MUST be
non-static members since the operand (or the left hand operand for
binary functions) is implicitly "this".

Quote:

2. Does the implicit "this" pointer passed by the nonstatic
operator()() get optimized away in a typical implementation?

For inlined functions, yes.

Quote:
std::less takes two arguments t1 and t2 and returns the result of
operator<(t1, t2). Since operator()() is nonstatic, though, in
addition to passing const references to t1 and t2, a const pointer to
this is also passed

Of course, operator () has to be applied to something. It's not applied
to the t1 or t2 arguments, it's applied to the functor object.

Yes, functors are ill-defined. But rather than hoking up the definition of
operator overloading to handle the case where an operand is explicitly
discarded, it would be better to fix the functor paradigm to allow a non-static
(named) member.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Thomas Tutone
Guest





PostPosted: Wed Dec 31, 2003 1:06 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

"James Kanze" wrote:
Quote:
"Tom" writes:

|> 1. Why does the standard not permit a functor to use a static
|> overload of operator()()?

What would it mean? A () operator requires a left operand.

That begs the question, though. Operator()() requires a left-operand
because the Standard requires that it be a non-static member function. But
as the std::less example below demonstrates, it may not actually USE that
left operand. My question was why not permit a static version of
operator()().

[SNIP]

Quote:
|> Consider, for example, the typical implementation of the Standard
|> Library's std::less functor:

|> template<class T
|> struct less : public binary_function<T, T, bool
|> {
|> bool operator()(const T& t1, const T& t2) const
|> {
|> return t1 < t2;
|> }
|> };

|> One reason the Standard Library uses functor templates instead of
|> function templates to pass to algorithms and associative containers
|> is that a functor is more readily inlined than the call via the
|> function pointer that the algorithm would otherwise be passed.

With which compiler? Constant propagation is one of the oldest
optimization techniques known -- it would be a very poor compiler which
would still generate an indirect function call if the pointer to a
function were a constant.

I wonder if we're talking about the same thing. I have in mind an example
like the following:

inline bool isGreater(int a, int b)
{
return a>b;
}

std::sort(vec.begin(), vec.end(), isGreater); // #1
vs.
std::sort(vec.begin(), vec.end(), std::greater<int>()); // #2

My point was std::sort's calls to the function object in #2 is more easily
inlined than std::sort's calls to function pointer in #1. But if I
understand you correctly, you are suggesting that any compiler that, with
optimizations enabled, failed to inline the call to isGreater in the above
example is "a very poor compiler." While I agree that a good compiler ought
to be able to inline #1, I suspect that a majority of the compilers in
widespread use today would qualify as "very poor compilers" in your eyes.
In any event, a number of others have suggested that function objects get
inlined more easily than function pointers in this context. For example:

"Function objects are usually faster than ordinary functions. The concept
of templates usually allows better optimization because more details are
defined at compile time. Thus passing function objects instead of ordinary
functions [to Standard Library algorithms] often results in better
performance." Josuttis, C++ Standard Library, Sec. 5.9, p. 127.

"A suitably-defined object serves as well as - and often better than - a
function. For example, it is easier to inline the application operator of a
class than to inline a function passed as a pointer to a function.
Consequently, function objects often execute faster than do ordinary
functions." Stroustrup, TC++PL (3d. ed.), Sec. 18.4, p. 515.

"Interestingly, if you were to compare the performance of the two calls to
sort (one using greater<double>, one using doubleGreater [an ordinary
function declared inline]), you'd almost certainly find that the one using
greater<double> was faster. For instance, I timed the two calls to sort on
..... four different STL platforms, each set to optimize for speed, and the
version using greater<double> was faster every time. . . . Because
[doubleGreater] is a pointer to a function, each time it's used inside sort,
compilers make an indirect function call. . . . Most compilers won't try to
inline calls to functions that are invoked through function pointers, even
if, as in this example, such functions have been declared inline and the
optimization appears to be straightforward." Meyers, Effective STL, Item
46, pps. 202-03.

Presumably the bar for compiler optimizations has gone up since these were
written, but I wonder if your optimization assumption is true yet.

Quote:
I think the reason why the library uses functional objects rather than
functions is more fundamental -- how on earth could it define the
typedef's for first_argument_type, second_argument_type and result_type
if it used a pointer to a function?

A fair point. But in fairness to me, I said that _one_ reason the Standard
Library uses functor templates instead of function templates was that the
functor was more readily inlined - I didn't suggest it was the _only_
reason.

Best regards,

Tom


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Thomas Tutone
Guest





PostPosted: Wed Dec 31, 2003 1:07 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

"Ron Natalie" wrote:
Quote:
"Tom" wrote:

1. Why does the standard not permit a functor to use a static
overload of operator()()?

Because operators that are defined with member functions MUST be
non-static members since the operand (or the left hand operand for
binary functions) is implicitly "this".

Fair enough, but my question was _why_, since in the context of Standard
Library functors the implicit "this" is often ignored.

[SNIP]

Quote:
Yes, functors are ill-defined. But rather than hoking up the definition
of
operator overloading to handle the case where an operand is explicitly
discarded, it would be better to fix the functor paradigm to allow a
non-static
(named) member.

Can you elaborate on what you mean by this?

Best regards,

Tom


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Potter
Guest





PostPosted: Wed Dec 31, 2003 8:58 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

On 30 Dec 2003 14:56:23 -0500, James Kanze <kanze (AT) alex (DOT) gabi-soft.fr>
wrote:

Quote:
Thomas8675309 (AT) yahoo (DOT) com (Tom) writes:

|> One reason the Standard Library uses functor templates instead of
|> function templates to pass to algorithms and associative containers
|> is that a functor is more readily inlined than the call via the
|> function pointer that the algorithm would otherwise be passed.

With which compiler? Constant propagation is one of the oldest
optimization techniques known -- it would be a very poor compiler which
would still generate an indirect function call if the pointer to a
function were a constant.

Here is a nice short example which generates little enough assembler to
read. Do you have a compiler that inlines the inner call of the second
call?

inline bool comp (int a, int b) {
return a < b;
}
template inline bool compare (T const& a, T const& b, C c) {
return c(a, b);
}
struct Comp {
bool operator() (int a, int b) {
return a < b;
}
};
bool f (int a, int b) {
return compare(a, b, Comp()) && compare(a, b, comp);
}

Quote:
I think the reason why the library uses functional objects rather than
functions is more fundamental -- how on earth could it define the
typedef's for first_argument_type, second_argument_type and result_type
if it used a pointer to a function?

Actually, all of the algorithms are very carefully written to never use
that stuff. The template parameter may be either a functor or a pointer
to function. The types are available from the iterator traits. Only
fools like me who try to write copy_if in terms of remove_copy_if and
the not functor need these things. Even the associatives are written
so that a pointer to function may be used for the compare.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Jonathan Turkanis
Guest





PostPosted: Wed Dec 31, 2003 9:36 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote


"Thomas Tutone" <Thomas8675309NO_SPAM (AT) yahoo (DOT) com> wrote

Quote:
"James Kanze" wrote:
"Tom" writes:

|> 1. Why does the standard not permit a functor to use a static
|> overload of operator()()?

What would it mean? A () operator requires a left operand.

That begs the question, though. Operator()() requires a left-operand
because the Standard requires that it be a non-static member function.
But
as the std::less example below demonstrates, it may not actually USE that
left operand. My question was why not permit a static version of
operator()().

I think the point is that there is no natural syntax for invoking the
operator. Typically one ivokes a static member function like so

MyClass::static_function(arguments);

Having to use the notation

MyClass::operator() (arguments)

misses the point of operator overloading: one is supposed to be able to use
the ordinary function call syntax. You might suggest

MyClass(arguments);

but this is a constructor invocation. What syntax do you suggest?

Best Regards,
Jonathan



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gabriel Dos Reis
Guest





PostPosted: Wed Dec 31, 2003 9:38 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

James Kanze <kanze (AT) alex (DOT) gabi-soft.fr> writes:

Quote:
Thomas8675309 (AT) yahoo (DOT) com (Tom) writes:

|> Two questions:

|> 1. Why does the standard not permit a functor to use a static
|> overload of operator()()?

What would it mean? A () operator requires a left operand.

A () operator requires a left operand because?

--
Gabriel Dos Reis
[email]gdr (AT) integrable-solutions (DOT) net[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gabriel Dos Reis
Guest





PostPosted: Wed Dec 31, 2003 9:38 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

"Ron Natalie" <ron (AT) sensor (DOT) com> writes:

Quote:
"Tom" <Thomas8675309 (AT) yahoo (DOT) com> wrote

Two questions:

1. Why does the standard not permit a functor to use a static
overload of operator()()?

Because operators that are defined with member functions MUST be
non-static members since the operand (or the left hand operand for
binary functions) is implicitly "this".

Well, that same argument could be made for any member function (since
what one defined is a function, not an operator), yet we have static
member functions.

Having said that, I can only speculate about that rule: It is a
general, simple, rule -- as opposed to a long list of special cases.
D&E has a report on why the copy-and-assignment operator has been
required a non-static member function. I guess the constraints on
that operator were carried over to the general operators.

--
Gabriel Dos Reis
[email]gdr (AT) integrable-solutions (DOT) net[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Hyman Rosen
Guest





PostPosted: Thu Jan 01, 2004 2:03 am    Post subject: Re: Why prohibit static operator()()? Reply with quote

Gabriel Dos Reis wrote:
Quote:
Well, that same argument could be made for any member function (since
what one defined is a function, not an operator), yet we have static
member functions.

Sure, but the only way to invoke operator() as an operator is to use it
with an object of its class. Normal static methods have the Name::Func()
as an alternative way to be called.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gabriel Dos Reis
Guest





PostPosted: Thu Jan 01, 2004 2:04 am    Post subject: Re: Why prohibit static operator()()? Reply with quote

"Jonathan Turkanis" <technews (AT) kangaroologic (DOT) com> writes:

Quote:
"Thomas Tutone" <Thomas8675309NO_SPAM (AT) yahoo (DOT) com> wrote in message
news:N2qIb.566171$0v4.22851349 (AT) bgtnsc04-news (DOT) ops.worldnet.att.net...
"James Kanze" wrote:
"Tom" writes:

|> 1. Why does the standard not permit a functor to use a static
|> overload of operator()()?

What would it mean? A () operator requires a left operand.

That begs the question, though. Operator()() requires a left-operand
because the Standard requires that it be a non-static member function.
But
as the std::less example below demonstrates, it may not actually USE that
left operand. My question was why not permit a static version of
operator()().

I think the point is that there is no natural syntax for invoking the
operator.

I don't believe it.

Quote:
Typically one ivokes a static member function like so

MyClass::static_function(arguments);

One also invokes such functions as

object_expression.static_function(arguments);

Quote:
Having to use the notation

MyClass::operator() (arguments)

misses the point of operator overloading: one is supposed to be able to use
the ordinary function call syntax.

One is supposed to. But one is one required to. How do you apply
your logic to the following?

#include <iostream>
#include <ostream>

struct A {
operator void() const { std::cout << "Hi" << std::endl; }
};

int main() { (void)A(); }

Quote:
You might suggest

MyClass(arguments);

but this is a constructor invocation. What syntax do you suggest?

There is no need to invent new syntax. The syntax is already there.
The only thing it takes removing a *semantic* constraint.

--
Gabriel Dos Reis
[email]gdr (AT) integrable-solutions (DOT) net[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Gabriel Dos Reis
Guest





PostPosted: Thu Jan 01, 2004 12:34 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

Hyman Rosen <hyrosen (AT) mail (DOT) com> writes:

Quote:
Gabriel Dos Reis wrote:
Well, that same argument could be made for any member function (since
what one defined is a function, not an operator), yet we have static
member functions.

Sure, but the only way to invoke operator() as an operator is to use it
with an object of its class.

You're describing the current stituation; you're not giving a reason
that explains why that should be that way.

Quote:
Normal static methods have the Name::Func() as an alternative way to
be called.

Here is where the confusion lies.

What you said above is *one* possible syntax for the call. I see
nothing wrong with extending it to usual operators -- surely, that
won't be a real invention since we already have similar situation with
allocating and deallocating functions.

What "static" means for member function is change from the "normal"
calling sequence of non-static member function call -- by
suppressing the hidden or implied or implicit object (pointed-to by
"this" -- which is non-existant for static member function).
That means that, for an object-expression "e", a static member
function "f" and an arguments list "args", you can say "e.f(args)",
just like for "ordinary" non-static member functions.

Now, if "C" happen to be the class-type of "e" or a derived class of the
class-type of "e", you can say "C::f(args)".
Please, notice in that case, "f" is *name* of the function. For an
operator "@", the correponding operator function is named "operator @".
It would make perfect sense to say "C::operator()(args)" if you don't
happen to have an object expression handy which you would like to
make the call with. Surely, you would not benefit from the other
"natural" possibility, but "being able to benefit from a possibility"
is not a duty, it is an option. I can understand why some people would
like to have that option. There certainly are reasons for the current
situation, but the argument you gave does not look compeling.


--
Gabriel Dos Reis
[email]gdr (AT) integrable-solutions (DOT) net[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Jonathan Turkanis
Guest





PostPosted: Thu Jan 01, 2004 12:35 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote


"Gabriel Dos Reis" <gdr (AT) integrable-solutions (DOT) net> wrote

Quote:
"Jonathan Turkanis" <technews (AT) kangaroologic (DOT) com> writes:

| "Thomas Tutone" <Thomas8675309NO_SPAM (AT) yahoo (DOT) com> wrote in message
| news:N2qIb.566171$0v4.22851349 (AT) bgtnsc04-news (DOT) ops.worldnet.att.net...
| > "James Kanze" wrote:
| > > "Tom" writes:
|
| > > |> 1. Why does the standard not permit a functor to use a static
| > > |> overload of operator()()?
|
| > > What would it mean? A () operator requires a left operand.
|
| > That begs the question, though. Operator()() requires a left-operand
| > because the Standard requires that it be a non-static member
function.
| But
| > as the std::less example below demonstrates, it may not actually USE
that
| > left operand. My question was why not permit a static version of
| > operator()().
|
| I think the point is that there is no natural syntax for invoking the
| operator.

I don't believe it.

| Typically one ivokes a static member function like so
|
| MyClass::static_function(arguments);

One also invokes such functions as

object_expression.static_function(arguments);

Aha! I see now. You want static member functions which will almost always be
invoked on class instances, to avoid having to pass 'this'. Is that it?

Clearly, invoking operators explicitly using 'operator' should be avoided
whenever possible (and it almost always is); also, invoking static members
on class instances is probably best avoided, because it makes it hard for
the casual observer to see what is really going on. It seems like a bad idea
to introduce a language feature which can only be used in these two ways.

The potential for optimization seems doubtful, too. If operator() can't be
inlined, I doubt the performance impact of passing the implicit 'this' will
be significant. You can always have an inline operator() call a static
member function.

Quote:

One is supposed to. But one is one required to. How do you apply
your logic to the following?

#include #include
struct A {
operator void() const { std::cout << "Hi" << std::endl; }
};

int main() { (void)A(); }


Occasionally one needs to call conversion operators explicitly -- is that
your point? Or do you want to introduce static conversion operators, too?

Jonathan





[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Kanze
Guest





PostPosted: Thu Jan 01, 2004 10:13 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

"Thomas Tutone" <Thomas8675309NO_SPAM (AT) yahoo (DOT) com> writes:

Quote:
"James Kanze" wrote:
"Tom" writes:

|> 1. Why does the standard not permit a functor to use a static
|> overload of operator()()?

What would it mean? A () operator requires a left operand.

That begs the question, though. Operator()() requires a
left-operand because the Standard requires that it be a non-static
member function.

No. It requires a left operand because it is a function call operator,
and in C and in C++, a function call operator requires a left operand.

In general, none of the overloaded operators can be static members.
They can be either free functions, or non static member functions. I
can write either MyClass::operator+( MyClass const& right ) const, or
operator+( MyClass const& left, MyClass const& right ). In theory,
there is nothing that would prevent this from being allowed for
operator() as well:
void MyClass::operator()( int x ) const ;
or
void operator()( MyClass const& f, int x ) ;
both being called:
MyClass f ;
f( 1 ) ;
But in both cases, you need a MyClass object. It is, in the end, what
determines what function is actually called.

Quote:
But as the std::less example below demonstrates, it may not actually
USE that left operand.

The left operand may not be used in the fucntion, but it is determinant
as to what operator() is called. If I don't have an instance of
std::less, how is the compiler supposed to guess that it is the
overloaded operator() of that class that I want to call.

Quote:
My question was why not permit a static version of operator()().

Because there is no syntax which would permit calling it?

Quote:
[SNIP]

|> Consider, for example, the typical implementation of the
|> Standard Library's std::less functor:

|> template<class T
|> struct less : public binary_function<T, T, bool
|> {
|> bool operator()(const T& t1, const T& t2) const
|> {
|> return t1 < t2;
|> }
|> };

|> One reason the Standard Library uses functor templates
|> instead of function templates to pass to algorithms and
|> associative containers is that a functor is more readily
|> inlined than the call via the function pointer that the
|> algorithm would otherwise be passed.

With which compiler? Constant propagation is one of the oldest
optimization techniques known -- it would be a very poor compiler
which would still generate an indirect function call if the
pointer to a function were a constant.

I wonder if we're talking about the same thing. I have in mind an
example like the following:

inline bool isGreater(int a, int b)
{
return a>b;
}

std::sort(vec.begin(), vec.end(), isGreater); // #1
vs.
std::sort(vec.begin(), vec.end(), std::greater<int>()); // #2

My point was std::sort's calls to the function object in #2 is more
easily inlined than std::sort's calls to function pointer in #1.

Is it? If the compiler can see the code to std::sort, and the call, it
should have no problem propagating the constant expression &isGreater
through all of the loops. But to be frank, I don't know why, but when I
responded to your posting, my mind was fixed on inlined functions -- if
std::sort is inlined, it is a poor optimizer which doesn't inline
isGreater. If it isn't inlined, the question is much more complex, and
while there do exist compilers which presumably would inline it IF (and
only if) the function turned out to be in a critical path, they aren't
very common.

I think that the key here is that if you have several different
functions with the signature bool(int, int), you will only get one
instantiation of std::sort. Whereas to avoid code bloat with the
functional objects, you have to use some sort of handle object which
forwards to the actual object, via a virtual function or something
similar. Of course, in many contexts, that is an argument against
functional objects:-).

Quote:
But if I understand you correctly, you are suggesting that any
compiler that, with optimizations enabled, failed to inline the call
to isGreater in the above example is "a very poor compiler."

If std::sort is an exported template, I suspect that I was wrong. If it
isn't exported, and the compiler can see the implementation of std::sort
*and* the implementation of isGreater when it instantiates the template,
there is really no excuse for not propagating the constant &isGreater
through the loop, and inlining the call. Supposing, of course, that the
compiler is optimizing for speed at the expense of space.

In the end, it is a time vs. space trade-off. The use of value
semantics for the comparison functional object more or less favors time;
to use two different functions, I need two different types, and thus two
different instantiations of the template (with the resulting code
bloat). Alternatively, I can use a pointer-like object, say a handle to
a class with a virtual function.

Quote:
While I agree that a good compiler ought to be able to inline #1, I
suspect that a majority of the compilers in widespread use today
would qualify as "very poor compilers" in your eyes.

Well, they do, but I'll have to take back about it being because of
this:-).

Quote:
In any event, a number of others have suggested that function
objects get inlined more easily than function pointers in this
context. For example:

"Function objects are usually faster than ordinary functions. The
concept of templates usually allows better optimization because more
details are defined at compile time. Thus passing function objects
instead of ordinary functions [to Standard Library algorithms] often
results in better performance." Josuttis, C++ Standard Library,
Sec. 5.9, p. 127.

"A suitably-defined object serves as well as - and often better than
- a function. For example, it is easier to inline the application
operator of a class than to inline a function passed as a pointer to
a function. Consequently, function objects often execute faster
than do ordinary functions." Stroustrup, TC++PL (3d. ed.),
Sec. 18.4, p. 515.

"Interestingly, if you were to compare the performance of the two
calls to sort (one using greater<double>, one using doubleGreater
[an ordinary function declared inline]), you'd almost certainly find
that the one using greater<double> was faster. For instance, I
timed the two calls to sort on .... four different STL platforms,
each set to optimize for speed, and the version using
greater<double> was faster every time. . . . Because [doubleGreater]
is a pointer to a function, each time it's used inside sort,
compilers make an indirect function call. . . . Most compilers won't
try to inline calls to functions that are invoked through function
pointers, even if, as in this example, such functions have been
declared inline and the optimization appears to be straightforward."
Meyers, Effective STL, Item 46, pps. 202-03.

Presumably the bar for compiler optimizations has gone up since
these were written, but I wonder if your optimization assumption is
true yet.

Well, I've always set high standards:-). But for non-inlined functions,
I think that this optimisation is still beyond the capabilities of most
compilers. Including some very good ones. (There is also the question
of what is meant by "good". The best compiler I have access to is
Comeau's, but it doesn't do any optimization.)

Thinking about it, however, I wonder what the correct solution really
is. All of the above passages concern pure runtime optimization, and
none of them mention the actual trade-off involved -- extensive code
bloat. If the code bloat is acceptable, the inlining is possible with a
pointer to a function as well, although I will admit that it requires a
considerably more advanced compiler -- and that most current compilers
aren't there yet (but many aren't that far).

Another interesting point (which doesn't take anything from your initial
argument) is that the decision to inline or not is really taken at the
wrong place -- it's not a given function that I need to inline, but a
given call. A (very) few compilers are capable of doing this today --
they chose which calls to inline according to profiling output, and may
inline the function f in one case, and not another. At least one
compiler I have heard about is capable of inlining virtual functions in
such cases; presumably, it would also have no problem with isGreater in
your example either. (Note that the Java Hot Spot compiler for Windows
does this as well -- and it is NOT just an experimental compiler.)

If this sort of technology becomes practical in widespread use, then it
is the function version which we should prefer -- we avoid code bloat,
except in the cases where the code bloat actually speeds up a critical
loop.

Quote:
I think the reason why the library uses functional objects rather
than functions is more fundamental -- how on earth could it
define the typedef's for first_argument_type,
second_argument_type and result_type if it used a pointer to a
function?

A fair point. But in fairness to me, I said that _one_ reason the
Standard Library uses functor templates instead of function
templates was that the functor was more readily inlined - I didn't
suggest it was the _only_ reason.

Yes. I think I have to acknowledge your point. Given current compiler
technologies, anyway, and supposing that std::sort (or whatever) is not
itself inlined. (If std::sort is inlined, I stand by my argument -- the
technology necessary to inline the function has been around for decades,
and should be a standard part of any C/C++ optimizer. I don't know why,
but when I responded to your posting, I was thinking of inlined
functions.)

As for the actual reasons -- it's fully possible that the original
authors chose functional objects for performance reasons (they were
developing with a compiler with very limited resources), and only
realized afterwards the additional possibilities, such as the typedefs,
that this gave them. Still, I prefer to give them the benefit of the
doubt, and believe that they had a brillant design idea, that just
happened to also result in better performance with poorer compilers
(poorer, in this case, to be taken literally: compilers having less
resources with which to do their job, and not necessarily of lower
quality).

--
James Kanze mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
James Kanze
Guest





PostPosted: Thu Jan 01, 2004 10:21 pm    Post subject: Re: Why prohibit static operator()()? Reply with quote

Gabriel Dos Reis <gdr (AT) integrable-solutions (DOT) net> writes:

Quote:
"Jonathan Turkanis" <technews (AT) kangaroologic (DOT) com> writes:

| "Thomas Tutone" <Thomas8675309NO_SPAM (AT) yahoo (DOT) com> wrote in message
| news:N2qIb.566171$0v4.22851349 (AT) bgtnsc04-news (DOT) ops.worldnet.att.net...
| > "James Kanze" wrote:
| > > "Tom" writes:

| > > |> 1. Why does the standard not permit a functor to use a
| > > |> static overload of operator()()?

| > > What would it mean? A () operator requires a left operand.

| > That begs the question, though. Operator()() requires a
| > left-operand because the Standard requires that it be a
| > non-static member function. But as the std::less example below
| > demonstrates, it may not actually USE that left operand. My
| > question was why not permit a static version of operator()().

| I think the point is that there is no natural syntax for invoking
| the operator.

I don't believe it.

And yet, that's what I wrote. An operator() requires a left operand.
Whether it is a built-in operator(), or a user defined version.

In fact, the rule that an operator overload cannot be a static member is
general; it holds for all overloaded operators, not just for operator().

Quote:
| Typically one ivokes a static member function like so

| MyClass::static_function(arguments);

One also invokes such functions as

object_expression.static_function(arguments);

In which case, you need an object. So where is the problem with making
it a non-static member?

Quote:
| Having to use the notation

| MyClass::operator() (arguments)

| misses the point of operator overloading: one is supposed to be
| able to use the ordinary function call syntax.

One is supposed to. But one is one required to. How do you apply
your logic to the following?

#include #include
struct A {
operator void() const { std::cout << "Hi" << std::endl; }
};

int main() { (void)A(); }

Neat. That's a new form of obfuscation, one of the rare forms which I
haven't seen yet in actual code.

How is this relevant to the current discussion?

Quote:
| You might suggest

| MyClass(arguments);

| but this is a constructor invocation. What syntax do you suggest?

There is no need to invent new syntax. The syntax is already there.
The only thing it takes removing a *semantic* constraint.

I'm not sure what your point is. Are you saying that there is some sort
of obscure trick like the above which can invoke the function? Or are
you simply coming back to your previous point -- that you can invoke a
static member function on an object already?

In the latter case, I think it is worth discussing. However, I would
enlarge the discussion to include static virtual functions. In the end,
it is a similar problem: you need an object to call the correct
function, but you don't need the object within the function, once it has
been called.

--
James Kanze mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2, 3, 4, 5  Next
Page 1 of 5

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.