Topic: References to functions allowed?
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/25 Raw View
On 19 Jan 1999 15:51:29 GMT, AllanW@my-dejanews.com
An amusing reply, but in previous times, I had seriously considered why
C++ doesn't have self-modifying functions. The existence of
self-modifying functions seem to imply the existence of nested or lambda
functions.
>Consider that C++ can do almost anything that assembly language can do.
>But there is one powerful programming technique that has fallen out of
>favor recently, a mood swing which has so blinded the C++ standardization
>committee that it wasn't even considered for inclusion in the language.
>Which is bad, because the technique I am referring to is time-honored,
>well-understood, and very very powerful. Of course I cannot be talking
>about anything other than self-modifying code.
There is much time spent modifying the functions, which is probably one
reason why they didn't include it in the language. A second reason is
that if functions were modifiable, then a function couldn't have a
fixed address in memory. Instead, we would have a pointer/reference to
the actual function. This incurs a small space and time overhead. The
space overhead is because we need a pointer to the function along with
the function. The time overhead is because we need to dereference the
pointer each time we want to call the function. Also, forget about
inlining.
> #include <iostream>
> const int MAXVAL = 5;
> int nextval(int) { return 0; }
> int decrement(int);
> int increment(int x) {
> ++x; // Must update BEFORE overwrite
> if (x>=MAXVAL) {
> int (&me)(int) = nextval;
> int (&const other)(int) = decrement;
> me = other; // Overwrite nextval() with copy of decrement
> }
> return x;
> }
> int decrement(int x) {
> --x; // Must update BEFORE overwrite
> if (x<=0) {
> int (&me)(int) = nextval;
> int (&const other)(int) = increment;
> me = other; // Overwrite nextval() with copy of increment
> }
> return x;
> }
>
> int main() {
> // Also inits nextval() with copy of increment:
> int v = decrement(1);
> std::cout << v;
> for (int i=1; i<=20; ++i) std::cout << ',' << (v=nextval(v));
> std::cout << std::endl;
> }
> // Output: 0,1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1,0
BTW, why not just say "nextval=increment" or "nextval=decrement"?
Besides, I don't think the technique will be much used. For in general,
the functions 'increment' and 'decrement' would have to contain static
variables to represent their state. This way, they know when to mutate
the function 'nextval'. For example, each could have a counter that
goes from one to five. When the counter hits five, we reset it to zero
and mutate the function 'nextval'. In your case, the variable 'x'
passed to the function serves as the state variable. But this seems
like a special case, for in general, state variables would be required.
The problem with static variables is that there is only one copy of
them. This rules out multi-threading. Single-threading is a problem
too because we might want to interleave two sequences. This leaves us
with one possibility -- make 'nextval' an object of type NextVal with
the state variables as private data members.
What we've described is the wrapper technique to get the effect of
mutating functions. The class NextVal is a wrapper that contains
within it a pointer to a function (or a polymorphic class, or
whatever), along with a couple of state variables. The class NextVal
behaves either as the function 'increment' or the function
'decrement'. It changes its behaviour according to input from the
outside world. The end result is the effect of mutating functions.
--------------------------------------------------------------
#include <cstddef> // size_t
//
// pre-existing functions
//
int increment(int x) { return x+1; }
int decrement(int x) { return x-1; }
//
// class to coordinate the above two functions
//
class NextVal
{
class Function
{
private:
size_t indx;
int (*function)(int);
static int (*const functions[2])(int);
public:
Function() : indx(0), function(functions[indx]) { }
Function& operator++()
{
const size_t N=sizeof(functions)/sizeof(*functions);
function=functions[(function==functions[N-1])?(indx=0):++indx];
return *this;
}
int operator()(int x) { return (*function)(x); }
};
private:
int counter;
Function function;
public:
NextVal() : counter(), function() { }
int operator()(int num)
{
int newnum=function(num);
if (++counter==5) { ++function; counter=0; }
return newnum;
}
};
int (*const NextVal::Function::functions[2])(int)={&::increment,&::decrement};
//
// test driver
//
#include <iostream>
int main()
{
NextVal v;
int j;
cout << (j=v(0));
for (int i=0; i<20; i++) cout << ',' << (j=v(j));
}
--------------------------------------------------------------
>As you can see, the first thing main() does is to call decrement(). That
>function causes the code in function increment() to overwrite function
>nextval(). From then on we call nextval() only. When we have incremented
>as much as we want to, nextval() overwrites itself with a copy of
>decrement(), which takes effect next time the function is called.
There is time spent overwriting the function.
>I hear some of you object right now. "Couldn't you accomplish the same
>thing by having two classes with virtual functions, and then overwriting
>the vtables with the new function addresses?" Perhaps, but this gets
>tricky. A simpler technique would be to modify the vptr itself, to point
>to the other vtable. But even this crystal-clear idea has drawbacks; it
>just isn't a general-purpose solution to the problem. To see why, imagine
>that main() is a legacy function that you cannot make changes to. Since
>main() calls nextval() directly, the only general-purpose solution to
>the problem is to overwrite the code in nextval() at run time.
Yes, any of the C++ techniques would work. If we're coding in C++ but
maintaining legacy code written in C, then we can use the wrapper
technique. Just write a class like the one above. (The 'indx' field
is essentially a virtual pointer, so the class NextVal above is
essentially polymorphic.)
If we're coding in C and maintaining legacy code in C, then the wrapper
technique is still possible because it is possible to have classes in
C too. Like this:
// NextVal.h
struct NextVal;
NextVal * NextVal_construct();
void NextVal_destruct();
int NextVal_do(int);
// NextVal.c
#include "NextVal.h"
struct NextVal { ... }
...
>An even worse idea is to create a fancy version of nextval() with large
>if-then sections, or to use some method that checks flags (or anything
>else) and "dispatches" to some other function to do the actual work. As
>all assembly-language programmers know, irresponsible solutions like
>this cause extra memory fetches. For instance, a Cray computer might
>take as much as 20 nanoseconds longer if the above program were written
>in this way. If run 1000 times a day for 30 years, this would add up to
>well over 0.2 seconds -- that's 0.2 very expensive seconds of Cray CPU
>time, and also 0.2 seconds of your personal time that you could have
>spent with your loved ones, or simply relaxing.
:)
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/19 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
>In article <780f6f$kjs$1@engnews2.Eng.Sun.COM>, Steve Clamage
><stephen.clamage@sun.com> writes
>>
>>Sections 3.9.2 and 8.3.2 mention references to functions, and
>>section 8.5.3 gives this example of a reference to function:
>>
>> int (&rg)(int) = g; // rg refers to the function g
>Well I stand corrected, but this seems to buy us nothing while meaning
>that the strict rules for function names in C and C++ are different.
Yes. In C++ a function designator is converted automatically to
a pointer only when you need an rvalue. I don't think allowing
function pointers makes invalid any program that would otherwise
be valid. That is, I think it constitutes a pure extension to C.
> ... However what use is it?
I think it has the same uses as other kinds of references. One
primary use would be as a function parameter. For one thing, you
can assume the reference is always initialized and never null,
unlike a pointer.
I think the real reason why references to functions are allowed is
that there is no good reason to prohibit them. That is, allowing them
1. does not create any problems (that I know of);
2. adds no special cases to the language (functions have special
rules whether references are allowed or not);
3. removes one special case (we don't prohibit references to functions);
4. has at least some minor utility (as with references in general).
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: thp@vdo.ucr.edu (Tom Payne)
Date: 1999/01/20 Raw View
Steve Clamage (stephen.clamage@sun.com) wrote:
[...]
: I think the real reason why references to functions are allowed is
: that there is no good reason to prohibit them. That is, allowing them
: 1. does not create any problems (that I know of);
: 2. adds no special cases to the language (functions have special
: rules whether references are allowed or not);
: 3. removes one special case (we don't prohibit references to functions);
: 4. has at least some minor utility (as with references in general).
It would seem that each of these reasons would apply equally well to
adding references to arrays.
C/C++ sort of gives reference semantics to arrays and functions
already, in the sense that their names designate, not the entities
themselves, but their address. To compensate, the fundamental
operations on these kinds of entities (respectively, subscripting and
application-to-paramenters) have been changed to work on the addresses
of these entities rather than the entities themselves.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/01/20 Raw View
Siemel Naran wrote in message ...
<snip>
>But references to functions are legal. The compiler 'como' accepts..
<snip>
Siemel,
What's that 'como' compiler? You mean 'Comeau'? If this is the case, you may
want to spell it correctly.
Andrei
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/01/20 Raw View
Biju Thomas <bijuthom@ibm.net> writes:
>Steve Clamage wrote:
>>
>> Sections 3.9.2 and 8.3.2 mention references to functions, and
>> section 8.5.3 gives this example of a reference to function:
>>
>> int (&rg)(int) = g; // rg refers to the function g
>>
>Okay, thanks.
>What about references to members functions and references to member
>data.
It appears that references to (non-static) members are not allowed.
A pointer-to-(non-static)-member is a special category of type.
It is not like an ordinary pointer to an object or function.
It has special rules.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/20 Raw View
On 19 Jan 99 01:00:27 GMT, Biju Thomas <bijuthom@ibm.net> wrote:
>What about references to members functions and references to member
>data. Is the following legal?
No, see the quote from the standard in my other posting. They only
talk of pointers to member functions, pointers to non-member
functions, and references to non-member functions. There is no
talk of references to member functions. One reason is that the
syntax would be very strange.
>struct Foo {
> int f ();
> int d;
>};
>
>int (Foo::&rmf)() = Foo::f;
>int (Foo::&rmd) = Foo::d;
>
>Foo aFoo;
>
>int x = (aFoo.rmf)();
>int y = aFoo.rmd;
>
>Looks like valid syntax. But, I am not sure.
The syntax makes it look as if "aFoo" has members "rmf" and "rmd",
or that there are members Foo::rmf and Foo::rmd. This is certainly
not the case. Additionally, how would you deal with this
pathological case:
struct Foo {
int d;
int e;
};
int main() {
int Foo::&d = Foo::e;
Foo aFoo;
int x=aFoo.d; // use Foo::d or Foo::e
}
Hence there can only be pointers to members. This is probably why
C++ requires you to use the '&' sign when taking the address of a
member -- ie, there is no member to pointer decay, although many
compilers do it this way.
And a small aside. I often make the mistake of calling member
functions that take no arguments like this,
int f=object.func; // should be "int f=object.func()"
This gives me strange errors at compile time. If compilers
enforced the rule that you must use '&', then the above would be
meaningless, and I'd get a pretty decent error message.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/01/20 Raw View
thp@vdo.ucr.edu (Tom Payne) writes:
>Steve Clamage (stephen.clamage@sun.com) wrote:
>: Sections 3.9.2 and 8.3.2 mention references to functions, and
>: section 8.5.3 gives this example of a reference to function:
>: int (&rg)(int) = g; // rg refers to the function g
>So what would be the semantic difference between rg and pg where pg is
>declared:
> int (*pg)(int) = g; // pg points to the function g
>i.e., in what contexts would they produce different results?
Variable rg is a reference. You can't take its address, create a
pointer or reference to it, or change it to refer to some other
function.
Variable pg is a pointer. You can take its address, create a
pointer or reference to it, or change it to point to some other
function.
>This also raises a few more questions for me. It has been my
>(mis)understanding that the name of a function represents a
>function-pointer value (the address of the function) in all contexts
>except where it is the agrument of the sizeof operator and unary-&.
True in C, but not in C++. In C++ the function-to-pointer conversion
is applied when something of function type is used in a context
where an rvalue is needed. If you don't need an rvalue, you don't
get the conversion.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: tony@ns.cook.ml.org (Tony Cook)
Date: 1999/01/20 Raw View
Andrei Alexandrescu (alexandrescua@micromodeling.com) wrote:
: Siemel Naran wrote in message ...
: <snip>
: >But references to functions are legal. The compiler 'como' accepts..
: <snip>
: Siemel,
: What's that 'como' compiler? You mean 'Comeau'? If this is the case, you may
: want to spell it correctly.
<snip>
It's about as accurate as calling GNU C++ gcc or g++. como is the
command used to invoke the compiler.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Martijn Lievaart" <nobody@orion.nl>
Date: 1999/01/20 Raw View
Siemel Naran wrote in message ...
>
>And a small aside. I often make the mistake of calling member
>functions that take no arguments like this,
> int f=object.func; // should be "int f=object.func()"
>This gives me strange errors at compile time. If compilers
>enforced the rule that you must use '&', then the above would be
>meaningless, and I'd get a pretty decent error message.
>
VC 5 often gives an internal compiler error in this specific case. Talk
about strange errormessages ;^>
I'ld love to see your proposol in the next standard, it's just so much more
logical. I cannot think of any reason why this would not be possible, except
from breaking a lot of old code (but we can depricate it first).
Martijn
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/20 Raw View
Tom Payne wrote:
>
> Steve Clamage (stephen.clamage@sun.com) wrote:
>
> [...]
>
> : I think the real reason why references to functions are allowed is
> : that there is no good reason to prohibit them. That is, allowing them
> : 1. does not create any problems (that I know of);
> : 2. adds no special cases to the language (functions have special
> : rules whether references are allowed or not);
> : 3. removes one special case (we don't prohibit references to functions);
> : 4. has at least some minor utility (as with references in general).
>
> It would seem that each of these reasons would apply equally well to
> adding references to arrays.
References to arrays are allowed. Only arrays of references aren't.
Indeed, references to arrays are particulary useful if you want
to ensure that you really have an array of a given dimension.
Example:
typedef double twodouble[2];
void f(twodouble& i);
int main()
{
twodouble x;
double y[2];
double z[1];
double* p;
f(x); // Ok
f(y); // Ok
f(z); // Error: cannot convert double[1] to double[2]
f(p); // Error: cannot convert double* to double[2]
}
Also, it allows you to templatize on the array dimension.
For example:
template<int n> void clear(int (&arr)[n])
{
for(int i=0; i<n; ++i)
arr[i]=0;
}
This can be called with
int array[100];
clear(array);
which is less error prone than the usual interface for such
functions:
clear(array, 100); // don't forget to change if array size changes!
[...]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/20 Raw View
On 20 Jan 99 07:19:09 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:
>thp@vdo.ucr.edu (Tom Payne) writes:
>>: int (&rg)(int) = g; // rg refers to the function g
>> int (*pg)(int) = g; // pg points to the function g
>
>>i.e., in what contexts would they produce different results?
>Variable rg is a reference. You can't take its address, create a
>pointer or reference to it, or change it to refer to some other
>function.
Yes, you can take the address of a reference. The type of "&rg"
is "int (*)(int)".
Indeed, you can't make a reference to a reference, or a pointer
to a reference, or an array of references.
Note that you can make a reference or pointer to the object the
reference refers to.
Also, you can't do sizeof(rg) because you can't take the size of
a function.
>Variable pg is a pointer. You can take its address, create a
>pointer or reference to it, or change it to point to some other
>function.
Right, and the type of "&pg" would be "int (**)(int)".
And you can form a reference or pointer to "pg".
You can indeed repoint 'pg'. But 'pg' could very well have been
declared "int (*const pg)(int)=g" if we wanted to prevent
repointing.
Finally, typeid(rg) and typeid(pg) are different, and the strings
returned by name are different.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/20 Raw View
In article <780u86$vj4$1@nnrp1.dejanews.com>, AllanW@my-dejanews.com wrote:
...
> Consider that C++ can do almost anything that assembly language can do.
> But there is one powerful programming technique that has fallen out of
> favor recently,
> a mood swing which has so blinded the C++ standardization
> committee that it wasn't even considered for inclusion in the language.
> Which is bad, because the technique I am referring to is time-honored,
> well-understood, and very very powerful. Of course I cannot be talking
> about anything other than self-modifying code.
> that has fallen out of favor recently
Yeah, when Memory Management Units came into use :-)
> #include <iostream>
> const int MAXVAL = 5;
> int nextval(int) { return 0; }
> int decrement(int);
> int increment(int x) {
> ++x; // Must update BEFORE overwrite
> if (x>=MAXVAL) {
> int (&me)(int) = nextval;
> int (&const other)(int) = decrement;
> me = other; // Overwrite nextval() with copy of decrement
[code snipped]
...
> By the way, the code above has a minor problem. Note that the stub
> version of nextval() probably generates less code than either
> increment() or decrement(). When we try to overwrite the function,
> we'll... uh... get a memory overwrite. Detecting this can be as simple
> as inserting
> assert(sizeof(me)>=sizeof(other));
> into the appropriate place in both increment() and decrement(). Give
> yourself 10 points if you caught this on your own.
>
>
> 8^> :-) 8^> :-) 8^> :-) 8^> :-) 8^> :-) 8^>
Allan, was this whole post a joke? I am unsure as whether to respond
seriously or not. Where to begin...
--
"I don't like my edges rounded off" - Ani DiFranco
Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/01/21 Raw View
On 20 Jan 99 14:30:23 GMT, Martijn Lievaart <nobody@orion.nl> wrote:
>Siemel Naran wrote in message ...
>>And a small aside. I often make the mistake of calling member
>>functions that take no arguments like this,
>> int f=object.func; // should be "int f=object.func()"
>>This gives me strange errors at compile time. If compilers
>>enforced the rule that you must use '&', then the above would be
>>meaningless, and I'd get a pretty decent error message.
>VC 5 often gives an internal compiler error in this specific case. Talk
>about strange errormessages ;^>
>
>I'ld love to see your proposol in the next standard, it's just so much more
>logical. I cannot think of any reason why this would not be possible, except
>from breaking a lot of old code (but we can depricate it first).
What proposal are you talking about? I actually like the rule that
you have to use the '&' when taking the address of a member. So
I don't think the standard should change. Rather, implementors
should implement this peculiarity of the standard.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/01/21 Raw View
sbnaran@localhost.localdomain.COM (Siemel Naran) writes:
>On 20 Jan 99 07:19:09 GMT, Steve Clamage <clamage@Eng.Sun.COM> wrote:
>>thp@vdo.ucr.edu (Tom Payne) writes:
>>>: int (&rg)(int) = g; // rg refers to the function g
>>> int (*pg)(int) = g; // pg points to the function g
>>
>>>i.e., in what contexts would they produce different results?
>>Variable rg is a reference. You can't take its address, create a
>>pointer or reference to it, or change it to refer to some other
>>function.
>Yes, you can take the address of a reference. The type of "&rg"
>is "int (*)(int)".
The syntax &rg is valid, but it does not give you the address
of the reference. It gives you the address of what rg refers to.
By contrast, if you write &pg, you get the address of variable pg.
You cannot do that with references; C++ does not have the concept
of the address of a reference.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Martijn Lievaart" <nobody@orion.nl>
Date: 1999/01/21 Raw View
Siemel Naran wrote in message ...
>On 20 Jan 99 14:30:23 GMT, Martijn Lievaart <nobody@orion.nl> wrote:
>>Siemel Naran wrote in message ...
>
>>>And a small aside. I often make the mistake of calling member
>>>functions that take no arguments like this,
>>> int f=object.func; // should be "int f=object.func()"
>>>This gives me strange errors at compile time. If compilers
>>>enforced the rule that you must use '&', then the above would be
>>>meaningless, and I'd get a pretty decent error message.
>
>>VC 5 often gives an internal compiler error in this specific case. Talk
>>about strange errormessages ;^>
>>
>>I'ld love to see your proposol in the next standard, it's just so much
more
>>logical. I cannot think of any reason why this would not be possible,
except
>>from breaking a lot of old code (but we can depricate it first).
>
>What proposal are you talking about? I actually like the rule that
>you have to use the '&' when taking the address of a member. So
>I don't think the standard should change. Rather, implementors
>should implement this peculiarity of the standard.
>
About having to use & to take the adress of a function, instead of the
automatic decay to a pointer. I see it would not be completely orthogonal
with variabeles, but the current situation is not as well.
Martijn
--
My reply-to address is intentionally set to /dev/null
reply to mlievaart at orion in nl
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stanley@West.sun.com (Stanley Friesen [Contractor])
Date: 1999/01/21 Raw View
In article <785g5t$644$1@engnews2.Eng.Sun.COM>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>The syntax &rg is valid, but it does not give you the address
>of the reference. It gives you the address of what rg refers to.
>
>By contrast, if you write &pg, you get the address of variable pg.
>You cannot do that with references; C++ does not have the concept
>of the address of a reference.
For the very good reason that nothing in the standard actually requires
a reference occupy storage at all.
For instance the following use is perfectly conforming and reasonable:
extern LibClass libs_very_long_name_for_variable;
void func()
{
LibClass &small = libs_very_long_name_for_variable;
small->dosomething();
}
In the above the compiler can simply enter "small" into the symbol table as
an alias for the longer name. Such a reference need never show up at all
in the compiled binary.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1999/01/21 Raw View
In article <787pg7$47r@abyss.West.Sun.COM>, stanley@West.sun.com (Stanley
Friesen [Contractor]) wrote:
> In article <785g5t$644$1@engnews2.Eng.Sun.COM>,
> Steve Clamage <clamage@Eng.Sun.COM> wrote:
> >The syntax &rg is valid, but it does not give you the address
> >of the reference. It gives you the address of what rg refers to.
> >
> >By contrast, if you write &pg, you get the address of variable pg.
> >You cannot do that with references; C++ does not have the concept
> >of the address of a reference.
>
> For the very good reason that nothing in the standard actually requires
> a reference occupy storage at all.
Agreed.
> For instance the following use is perfectly conforming and reasonable:
>
> extern LibClass libs_very_long_name_for_variable;
>
> void func()
> {
> LibClass &small = libs_very_long_name_for_variable;
>
> small->dosomething();
> }
>
> In the above the compiler can simply enter "small" into the symbol table as
> an alias for the longer name. Such a reference need never show up at all
> in the compiled binary.
as-if rule. The same applies to a non-const pointer, for example:
extern LibClass libs_very_long_name_for_variable;
void func()
{
LibClass* small = &libs_very_long_name_for_variable;
small->dosomething();
}
(I guess you meant to use small.dosomething() above, so I fixed this in my
example)
The program cannot tell the difference, so the same optimizations can be
done in both cases.
I find references useful for their semantics, since there are no
optimizations that they allow that can't be done with const pointers whose
addresses aren't ever taken (correct about optimizations?).
--
"I don't like my edges rounded off" - Ani DiFranco
Gargantua Blargg | blargg@flash.net | http://www.flash.net/~blargg/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/01/18 Raw View
On 18 Jan 99 03:17:34 GMT, Biju Thomas <bijuthom@ibm.net> wrote:
>Does the C++ standard allow references to functions? For example, is the
>following legal?
>
>int f () {}
>
>int (&rf)() = f;
In discussing functions like
template <class Iter, class Predicate>
Predicate for_each(Iter begin, Iter end, Predicate pred);
the standard says that the function object 'pred' must be a pointer
to function, or an object with a function call operator (see, eg,
chapter 25, item 7).
Nothing is said of a reference to a function. This is because
references to functions add nothing new to the language. After all,
when dereferencing a pointer to a function, we don't need to use
the '*' operator. This freedom is necessary because the the
Predicate object in functions like for_each might be
[X] function objects, for which the '*' operator should not be used
[X] pointers to function, for which the '*' may or may not be used
This allows for_each to be written like this:
template <class Iter, class Predicate>
Predicate for_each(Iter begin, const Iter end, Predicate pred) {
while (begin!=end) pred(*begin);
return pred;
}
But references to functions are legal. The compiler 'como' accepts
it. From chapter 13.4 item 3, we read
Non-member functions and static member functions match targets
of type "pointer-to-function" or "reference-to-function".
Nonstatic member functions match targets of type
"pointer-to-member-function"; ...
There is no such thing as a reference to a member function. The
term is mentioned in other places, like chapter 8.3.5 item 4, and
section 13.3 item 2. Whether references to a functions are a
useful concept, I don't know, but I think the answer is no.
--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/18 Raw View
In article <36A222B3.E51DFD28@ibm.net>, Biju Thomas <bijuthom@ibm.net>
writes
>Hello,
>
>Does the C++ standard allow references to functions? For example, is the
>following legal?
>
>int f () {}
>
>int (&rf)() = f;
But you have a type mismatch. On the lhs you have declared rf to be a
reference to a function.. and on the rhs f is a pointer to a function...
Would you expect:
int i;
int & ri = &i;
to compile?
In simple terms IMO I do not think there is any syntactic way that you
can write a reference to a function (*f does not work because under the
rules that is converted to a pointer)
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 1999/01/18 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
[...]
>
> In simple terms IMO I do not think there is any syntactic way that you
> can write a reference to a function (*f does not work because under the
> rules that is converted to a pointer)
Was that intended or just an oversight ?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/01/18 Raw View
In article <xajr9ssr1qx.fsf@korrigan.inria.fr>,
Gabriel Dos_Reis <gdosreis@sophia.inria.fr> wrote:
>Francis Glassborow <francis@robinton.demon.co.uk> writes:
>
>[...]
>
>>
>> In simple terms IMO I do not think there is any syntactic way that you
>> can write a reference to a function (*f does not work because under the
>> rules that is converted to a pointer)
>
>Was that intended or just an oversight ?
I expect it was intentional. C and C++ do everything they can to prevent
functions from being treated as ordinary objects. Any expression that
would have type function is always converted to pointer to function. This
happens much of the time to arrays as well, but even arrays can be put in
structures -- functions can't. There's no such thing as a function
L-value.
As another poster said, what's gained by allowing function references?
Consider the reasons that variable references are useful:
1. Pass by reference rather than copying. Since functions are converted to
pointers, this already happens.
2. Updating variables passed by reference. You can't assign to a function
name, so this is moot.
3. References can't be changed to refer to a different object. With a
function pointer, you can get this by declaring it const.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/18 Raw View
Gabriel Dos_Reis <gdosreis@sophia.inria.fr> writes:
>Francis Glassborow <francis@robinton.demon.co.uk> writes:
>[...]
>>
>> In simple terms IMO I do not think there is any syntactic way that you
>> can write a reference to a function (*f does not work because under the
>> rules that is converted to a pointer)
>Was that intended or just an oversight ?
I think it was an oversight on Francis' part. :-)
Sections 3.9.2 and 8.3.2 mention references to functions, and
section 8.5.3 gives this example of a reference to function:
int (&rg)(int) = g; // rg refers to the function g
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/19 Raw View
In article <xajr9ssr1qx.fsf@korrigan.inria.fr>, Gabriel Dos_Reis
<gdosreis@sophia.inria.fr> writes
>Francis Glassborow <francis@robinton.demon.co.uk> writes:
>
>[...]
>
>>
>> In simple terms IMO I do not think there is any syntactic way that you
>> can write a reference to a function (*f does not work because under the
>> rules that is converted to a pointer)
>
>Was that intended or just an oversight ?
I do not know, but in what case would it ever matter?
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Biju Thomas <bijuthom@ibm.net>
Date: 1999/01/19 Raw View
Steve Clamage wrote:
>
> Sections 3.9.2 and 8.3.2 mention references to functions, and
> section 8.5.3 gives this example of a reference to function:
>
> int (&rg)(int) = g; // rg refers to the function g
>
Okay, thanks.
What about references to members functions and references to member
data. Is the following legal?
struct Foo {
int f ();
int d;
};
int (Foo::&rmf)() = Foo::f;
int (Foo::&rmd) = Foo::d;
Foo aFoo;
int x = (aFoo.rmf)();
int y = aFoo.rmd;
Looks like valid syntax. But, I am not sure.
--
Regards,
Biju Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: thp@vdo.ucr.edu (Tom Payne)
Date: 1999/01/19 Raw View
Steve Clamage (stephen.clamage@sun.com) wrote:
: Gabriel Dos_Reis <gdosreis@sophia.inria.fr> writes:
: >Francis Glassborow <francis@robinton.demon.co.uk> writes:
: >[...]
: >>
: >> In simple terms IMO I do not think there is any syntactic way that you
: >> can write a reference to a function (*f does not work because under the
: >> rules that is converted to a pointer)
: >Was that intended or just an oversight ?
: I think it was an oversight on Francis' part. :-)
: Sections 3.9.2 and 8.3.2 mention references to functions, and
: section 8.5.3 gives this example of a reference to function:
: int (&rg)(int) = g; // rg refers to the function g
So what would be the semantic difference between rg and pg where pg is
declared:
int (*pg)(int) = g; // pg points to the function g
i.e., in what contexts would they produce different results?
This also raises a few more questions for me. It has been my
(mis)understanding that the name of a function represents a
function-pointer value (the address of the function) in all contexts
except where it is the agrument of the sizeof operator and unary-&.
1) If so, then wouln't g be an rvalue in the above?
2) If so, wouldn't this declaration need to be const?
3) If it were const wouldn't then the type of rg be reference
to an object of type const pointer to function-returning-int
etc. (Two levels of indirection.)
Tom Payne
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/19 Raw View
In article <780f6f$kjs$1@engnews2.Eng.Sun.COM>, Steve Clamage
<stephen.clamage@sun.com> writes
>
>Gabriel Dos_Reis <gdosreis@sophia.inria.fr> writes:
>
>>Francis Glassborow <francis@robinton.demon.co.uk> writes:
>
>>[...]
>
>>>
>>> In simple terms IMO I do not think there is any syntactic way that you
>>> can write a reference to a function (*f does not work because under the
>>> rules that is converted to a pointer)
>
>>Was that intended or just an oversight ?
>
>I think it was an oversight on Francis' part. :-)
>
>Sections 3.9.2 and 8.3.2 mention references to functions, and
>section 8.5.3 gives this example of a reference to function:
>
> int (&rg)(int) = g; // rg refers to the function g
Well I stand corrected, but this seems to buy us nothing while meaning
that the strict rules for function names in C and C++ are different. A
function name is always a pointer type in C which the function
'operator' dereferences. Now presumably we have to provide a conversion
rule for g (actually see 4.3) in the above (or to convert it to a
function pointer elsewhere). And CodeWarrior compiles such code.
However what use is it?
Suppose that we try it in a template:
template <typename T> void garbage(T t);
How are we to use this if T is a function type?
I cannot see how:
template <typename T> class rubbish { }
is any more useful.
Can anyone suggest anyway in which this facility provides any
functionality?
Now how do I dereference a function pointer to bind it to a reference?
Is this well formed?
int fn (int);
int (*fnptr)(int) = fn;
int (&fnref)(int) = static_cast<int ()(int)> fnptr;
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1999/01/19 Raw View
In article <36A222B3.E51DFD28@ibm.net>,
bijuthom@ibm.net wrote:
> Hello,
Hi!
> Does the C++ standard allow references to functions? For example, is the
> following legal?
>
> int f () {}
>
> int (&rf)() = f;
It ought to; it really ought to.
Consider that C++ can do almost anything that assembly language can do.
But there is one powerful programming technique that has fallen out of
favor recently, a mood swing which has so blinded the C++ standardization
committee that it wasn't even considered for inclusion in the language.
Which is bad, because the technique I am referring to is time-honored,
well-understood, and very very powerful. Of course I cannot be talking
about anything other than self-modifying code.
#include <iostream>
const int MAXVAL = 5;
int nextval(int) { return 0; }
int decrement(int);
int increment(int x) {
++x; // Must update BEFORE overwrite
if (x>=MAXVAL) {
int (&me)(int) = nextval;
int (&const other)(int) = decrement;
me = other; // Overwrite nextval() with copy of decrement
}
return x;
}
int decrement(int x) {
--x; // Must update BEFORE overwrite
if (x<=0) {
int (&me)(int) = nextval;
int (&const other)(int) = increment;
me = other; // Overwrite nextval() with copy of increment
}
return x;
}
int main() {
// Also inits nextval() with copy of increment:
int v = decrement(1);
std::cout << v;
for (int i=1; i<=20; ++i) std::cout << ',' << (v=nextval(v));
std::cout << std::endl;
}
// Output: 0,1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1,0
As you can see, the first thing main() does is to call decrement(). That
function causes the code in function increment() to overwrite function
nextval(). From then on we call nextval() only. When we have incremented
as much as we want to, nextval() overwrites itself with a copy of
decrement(), which takes effect next time the function is called.
I hear some of you object right now. "Couldn't you accomplish the same
thing by having two classes with virtual functions, and then overwriting
the vtables with the new function addresses?" Perhaps, but this gets
tricky. A simpler technique would be to modify the vptr itself, to point
to the other vtable. But even this crystal-clear idea has drawbacks; it
just isn't a general-purpose solution to the problem. To see why, imagine
that main() is a legacy function that you cannot make changes to. Since
main() calls nextval() directly, the only general-purpose solution to
the problem is to overwrite the code in nextval() at run time.
An even worse idea is to create a fancy version of nextval() with large
if-then sections, or to use some method that checks flags (or anything
else) and "dispatches" to some other function to do the actual work. As
all assembly-language programmers know, irresponsible solutions like
this cause extra memory fetches. For instance, a Cray computer might
take as much as 20 nanoseconds longer if the above program were written
in this way. If run 1000 times a day for 30 years, this would add up to
well over 0.2 seconds -- that's 0.2 very expensive seconds of Cray CPU
time, and also 0.2 seconds of your personal time that you could have
spent with your loved ones, or simply relaxing.
"But," say some language lawyers, "there are some compilers that attempt
to put all executable code into a 'ROM-able' segment. ROM can't be
overwritten!" This is true, and it represents the biggest menace to our
profession. Clearly there is ONLY ONE reason for compilers to generate
code like this: To threaten our God-given right to create code that
modifies itself. Compiler writers will continue to act in antisocial
ways such as this until we hit them in the pocketbook. BOYCOTT! We must
all boycott any compiler that tries to move your code somewhere where you
can't modify it!
Note that self-modifying code is not the only useful purpose of
references to functions. There's also the issue of function sizes. For
instance, suppose that your program has profiled two provably-correct
functions, FunctionA() and FunctionB(), either one of which can be used
in your program. If you have found them to have almost identical run-time
charactaristics, then you will want to use whichever function has a
smaller memory footprint. But you can't compare sizeof(FunctionA) to
sizeof(FunctionB) -- that compares the size of the function POINTERs,
which will always be equal. If you had a reference to the actual
function itself, sizeof() would give you a true number.
By the way, the code above has a minor problem. Note that the stub
version of nextval() probably generates less code than either
increment() or decrement(). When we try to overwrite the function,
we'll... uh... get a memory overwrite. Detecting this can be as simple
as inserting
assert(sizeof(me)>=sizeof(other));
into the appropriate place in both increment() and decrement(). Give
yourself 10 points if you caught this on your own.
8^> :-) 8^> :-) 8^> :-) 8^> :-) 8^> :-) 8^>
----
AllanW@my-dejanews.com is a "Spam Magnet".
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@sophia.inria.fr>
Date: 1999/01/19 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
> In article <xajr9ssr1qx.fsf@korrigan.inria.fr>, Gabriel Dos_Reis
> <gdosreis@sophia.inria.fr> writes
> >Francis Glassborow <francis@robinton.demon.co.uk> writes:
> >
> >[...]
> >
> >>
> >> In simple terms IMO I do not think there is any syntactic way that you
> >> can write a reference to a function (*f does not work because under the
> >> rules that is converted to a pointer)
> >
> >Was that intended or just an oversight ?
>
> I do not know, but in what case would it ever matter?
Just to curious to know why reference to function is allowed while
the Standard would not provide syntax to defined one.
--
Gabriel Dos Reis, <dosreis@cmla.ens-cachan.fr>
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Biju Thomas <bijuthom@ibm.net>
Date: 1999/01/18 Raw View
Hello,
Does the C++ standard allow references to functions? For example, is the
following legal?
int f () {}
int (&rf)() = f;
TIA
--
Regards,
Biju Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]