Hi, there.
Recently I was working on a problem where we want to save generic
closures in a data structure (a vector). The closure should work for
any data type and any method with pre-defined signature.
When developing this lib, I figured that the
pointer-to-member-function, although seemingly an attractive solution,
does not work well for us.
The size and the memory model of a generic PTMF is not guaranteed,
therefore, cannot be saved in a heterogeneous container.
My solution turned out to be a C callback function pointer.
That is, instead of using a "int T::(*f)()", use a "int (*f)(T*)".
Although a wrapper function that does the forward call is needed, it
solved our problem.
For instance:
instead of calling
add_closure(&ob j, &MyClass::f) ;
I do
int mywrapper(*MyCl ass pobj){
return pobj->f();
}
add_closure(&ob j, &mywrapper);
Here, 2 assumptions were made:
1. all pointers have the same size as void*
2. all function pointers have the same size.
Then, the annoying wrapper function makes me think:
Why PTMF in the first place?
What if the language generates the wrapper function implicitly and
makes MyClass::f a regular function pointer of type int (*)
(MyClass*)?
At least it can make my life much easier. And I wonder whose life will
it make harder?
Dislike the ptmf(pobj) syntax? Still like the pobj->ptmf()syntax ? No
problem, the language can still do that, as long as it guarantees the
binary memory model of a PTMF is a function pointer. I don't mind
doing a reinterpret_cas t here.
Well, just when I'm about to finish, my gut's feeling starts yelling
hard: "No! It can't be right. This must have been thought over 1000
times! You must be missing something here."
"All right, sir. so what am I missing here?"
Jul 22 '05
37 5019
Ben wrote: ... If standard does not make a guarantee here, I'll have to assume that it is NOT safe for a roundtrip between any two PTMs, generally speaking.
The standard _does_ make a guarantee here. The explicit guarantee is
given, once again, in 5.2.10/9.
--
Best regards,
Andrey Tarasevich
Andrey Tarasevich <an************ **@hotmail.com> wrote in message news:<MY******* *************@c omcast.com>... Ben wrote: It is safe between any two _PMFs_ (pointer-to-member-function) types. As it is safe between any two pointer-to-ordinary-function types.
<snip>
My experience with VC is limited to VC6 and I don't know how much it is different from VC7 in this respect. VC6 happens to support several PMF models. The default one is called "Best-case always", which means that VC6 is trying to optimize the size of PMFs by analyzing the class hierarchy and choosing the size of the PMF accordingly. The logic it uses is simple: if there's no multiple inheritance in the given class and any of its ancestors, then the only thing PMFs to member functions of this class need to store is the function's entry point (4 bytes long). No additional information is needed. Otherwise (i.e. there's multiple inheritance somewhere above in the hierarchy) VC6 would use fully functional PMFs (8 bytes long).
It is easy to demonstrate that this VC6's logic is flawed and will lead to non-standard conforming behavior in certain contexts (my original example is one of such contexts, 'reinterpret_ca st' round-trip is another, just to name a few). However, there are a couple of compiler options that will force VC6 to always use multiple-inheritance-compatible PMFs regardless of the inheritance structure (see '/vmg', '/vmm').
I'm pretty sure (although I could be wrong) that what you observe in your experiment with VC7 happens for similar reasons. The source and destination pointer types are so different internally that even 'reinterpret_ca st' refuses to convert one into another. Maybe you should check the compiler's documentation and see whether if describes some options similar to '/vm...' in VC6.
I have recently written an article on this topic. There have been many
attempts to 'hack' closure pointers into C++; most fail because of an
inadequate understanding of the implementation of member function
pointers.
My article documents exactly what popular compilers are doing. I also
provide an implementation that satisfies Ben's original goal: closure
pointers without the use of new. I also provide operator == and !=, a
significant limitation of boost::function . http://www.codeproject.com/cpp/FastDelegate.asp
Unfortunately, for MSVC and Intel C++, it's only possible with a nasty
hack. The portability is quite good: it works on MSVC 6, 7, 7.1, Gnu
3.2, and the latest versions of Intel C++ for Windows, Intel C++ for
Itanium, Digital Mars C++, Metrowerks (x86). It's also been compiled
on Comeau C++. Recently I've also got it working on BCB5.5, but that
version is not yet uploaded to the website.
There are a few errors in the article which I need to correct, but I
think you'll still find it an interesting read. It has *much* more
information than I've seen anywhere else.
Incidentally, if you use the /vmg option on VC6 (without specifying
/vmm or /vms), the compiler generates incorrect code!! In the virtual
inheritance case, it can end up calling the wrong function... Only
happens in fairly obscure circumstances, but it's an appalling bug.
They fixed this for VC7, but I haven't seen it mentioned anywhere.
-Don.
Am Mon, 14 Jun 2004 08:57:36 -0400 schrieb Jeff Flinn <NO****@nowhere .com>:
Thank you for responding. I like your proposal. There are things similar
to what I began. Others are less important. But I also have some questions:
To 3: My serialization can load newer files in older versions. I made bad
experience with serialization that could do only the other way.
I am doing this by saving the size of the object ( I do this for
inheritance levels also, so I can add members to a base class also. If an
inheritance Level is small I can still omit this. ) When deserializing a
newer file, any data after the members known in the old versions are
omitted and the formatter jumps to the point after the current object.
Deserializing an older file, standard values replace any missing data,
when the end of an onject is reached in the stream but still values are
demanded.
The syntax in your terms:
ar & SObject( pmData1, "mData1", pData1default );
I also thought about joining de- and serialization methods. I was just a
matter of blindness :-)
To 4: I don't want to save objects twice, so if I am the owner of an
object I do the above, but when I just point to an object owned by someone
else I do:
ar & SRef( pmData1, "mData1", pData1default );
The base should be done like:
ar & SBase( ... ) <- here I was passing a function pointer, now it is open
what I'll do, I also want to be able to save the base as "inline" and omit
the size of the base and therefore I cannot change the base class'
serialization later. Maybe good for small bases.
Also important for me is references to objects that are not yet serialized
when serializing or not yet deserialized when deserializing. I keep a hash
map of pointers and stream positions to resolve them at the end of the
serialization.
Oh, I jast saw that Point 5 is probably addressing this issue.
To 11:
how is this useful manner of xml serialization. I have two requirements
only: I want to control wether something is a node or an attribute. And I
want to control the name for the attributes and nodes. I cannot see this
in your code examples in your posting, but I assume that I will find it in
the library docs that I am going to read this evening. template< class Archive > void serialize( Archive& ar, const int version ) { ar & mData1; ar & mData2;
... }
Prepend the member serialization with:
ar & boost::serializ ation::base_obj ect<base_class_ of_T>(*this);
So, my problem regarding the function pointer is, that the functions are virtual. They have to be virtual, because if the object is serialized through a base class (this)pointer, I want the complete object to be serialized.
boost::serializ ation does not use/require a common base class for serialization, thereby avoids this problem.
Hmm, there`s something I did not understand. I guess the serialization
method can be virtual. Otherwise I couldn't pass an arbitrary Object, that
I point to via ObjectBase*, to the serializing mechanism. If the method is
virtual, do you make sure, when calling the serialize method, that the
version is called that belongs to the base class and not to the complete
object's class?
It seems this library is cloase to what I have/what I want. If it fits and
works well I will definitely need it. So, thank you for pointing me to it.
cheers
Ingo
--
Erstellt mit M2, Operas revolutionärem E-Mail-Modul: http://www.opera.com/m2/
~ Samba, more than a low cost File and Printer server ~
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =----- http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
"Ingo Nolden" <in**********@S PAMrecurdyn.org > wrote in message
news:op******** ******@news.uni v-angers.fr... Am Mon, 14 Jun 2004 08:57:36 -0400 schrieb Jeff Flinn
<NO****@nowhere .com>: Thank you for responding. I like your proposal. There are things similar
Woe, It's Robert Ramey's proposal not mine. I just use it( with great
pleasure).
to what I began. Others are less important. But I also have some
questions: To 3: My serialization can load newer files in older versions. I made bad
I've never come across a product that is forward-compatible before, or at
least was visibly so. When you operate on the data loaded with an older
version of the software, and then serialize, don't you lose information?
experience with serialization that could do only the other way. I am doing this by saving the size of the object ( I do this for inheritance levels also, so I can add members to a base class also. If an inheritance Level is small I can still omit this. ) When deserializing a newer file, any data after the members known in the old versions are omitted and the formatter jumps to the point after the current object.
You'd have to bring this up with Robert. You can join the boost devel
mailing list - via Yahoo Groups. I suppose you could derive your own archive
class that could accomodate this requirement.
Deserializing an older file, standard values replace any missing data, when the end of an onject is reached in the stream but still values are demanded.
This is how boost::serializ ation works but it's explicit with the version
info stored in the file. The syntax in your terms:
ar & SObject( pmData1, "mData1", pData1default );
I also thought about joining de- and serialization methods. I was just a matter of blindness :-)
To 4: I don't want to save objects twice, so if I am the owner of an object I do the above, but when I just point to an object owned by someone else I do:
ar & SRef( pmData1, "mData1", pData1default );
The base should be done like:
ar & SBase( ... ) <- here I was passing a function pointer, now it is open what I'll do, I also want to be able to save the base as "inline" and omit the size of the base and therefore I cannot change the base class' serialization later. Maybe good for small bases.
Also important for me is references to objects that are not yet serialized when serializing or not yet deserialized when deserializing. I keep a hash map of pointers and stream positions to resolve them at the end of the serialization.
Oh, I jast saw that Point 5 is probably addressing this issue.
I think so.
To 11:
how is this useful manner of xml serialization. I have two requirements only: I want to control wether something is a node or an attribute. And I want to control the name for the attributes and nodes. I cannot see this in your code examples in your posting, but I assume that I will find it in the library docs that I am going to read this evening. template< class Archive > void serialize( Archive& ar, const int version ) { ar & mData1; ar & mData2;
... }
Prepend the member serialization with:
ar & boost::serializ ation::base_obj ect<base_class_ of_T>(*this);
So, my problem regarding the function pointer is, that the functions
are virtual. They have to be virtual, because if the object is serialized through a base class (this)pointer, I want the complete object to be serialized. boost::serializ ation does not use/require a common base class for serialization, thereby avoids this problem.
Hmm, there`s something I did not understand. I guess the serialization method can be virtual. Otherwise I couldn't pass an arbitrary Object, that
No ClassBeingSeria lized::serializ e is not virtual.
I point to via ObjectBase*, to the serializing mechanism. If the method is virtual, do you make sure, when calling the serialize method, that the version is called that belongs to the base class and not to the complete object's class?
See "Pointers to Objects of derived Classes" under "Special Considerations"
in the documentation. Generally the library handles these issues
automatically. In cases not automaticlaly handled, you register your classes
using:
#include <boost/serialization/export.hpp>
...
BOOST_CLASS_EXP ORT_GUID(derive d_one, "derived_on e")
BOOST_CLASS_EXP ORT_GUID(derive d_two, "derived_tw o")
It seems this library is cloase to what I have/what I want. If it fits and works well I will definitely need it. So, thank you for pointing me to it.
Your welcome, I hope it helps.
Jeff Flinn
> I have recently written an article on this topic. There have been many attempts to 'hack' closure pointers into C++; most fail because of an inadequate understanding of the implementation of member function pointers.
-Don.
Don, I did not go through the gory details of the implementation, but
I love this article. Will recommend it to my friends.
I totally agree with you in that 'delegate' is a much more
preferable,type-safer and simpler solution than PTM. And it is more
OO.
One question about Ryazanov's code (that was my another solution tried
before posting here, very appealing indeed.), is it standard C++ to
have PTM as a template parameter? I'm not a language lawyer, but after
searching the internet the only thing found that can be used as
non-type parameter was "integral type". And don't think PTM is
integral type, is it?
Finally, I may not dare to use your code in production. I tend to
avoid all gray areas whenever I can (the standard but non-portable
reinterpret_cas t of PMF is another gray area that I will stay away
from).
My current solution would be: either my plain wrapper function where I
gain efficiency, or boost:function where I pay some runtime overhead
but gain functor support.
Just hope as you said, 'delegate' can be included in the next release
of the language.
Best Regards, be****@combined .com (Ben) wrote in message news:<24******* *************** ****@posting.go ogle.com>... I have recently written an article on this topic. There have been many attempts to 'hack' closure pointers into C++; most fail because of an inadequate understanding of the implementation of member function pointers.
-Don. Don, I did not go through the gory details of the implementation, but I love this article. Will recommend it to my friends.
I totally agree with you in that 'delegate' is a much more preferable,type-safer and simpler solution than PTM. And it is more OO.
I think that PTM is horribly broken. Allowing you to specify an
overridden function from the derived class instead of through the base
class was IMHO a tragic mistake. That tiny bit of functionality came
at an enormous cost.
One question about Ryazanov's code (that was my another solution tried before posting here, very appealing indeed.), is it standard C++ to have PTM as a template parameter? I'm not a language lawyer, but after searching the internet the only thing found that can be used as non-type parameter was "integral type". And don't think PTM is integral type, is it?
It is standard, but a bit wierd. PTM is not integral type. Instead,
it's a *name-based* template parameter, quite distinct from normal
parameters and from integral non-type parameters. The syntax is ugly,
so I'm not sure what theyintened it to be used for. Compiler support
for it is patchy, but improving. I would class it as a light gray
area.
Unfortunately, because of its behaviour with inline functions, you
can't use operator == which is a real shame.
Finally, I may not dare to use your code in production. I tend to avoid all gray areas whenever I can (the standard but non-portable reinterpret_cas t of PMF is another gray area that I will stay away from).
The relationship between "standard" and "portable" is interesting...
the surpising thing about my code is that it's the allegedly standard
part that requires a hack; the non-standard part (invoking the
function once it's been cast) is no problem at all. My current solution would be: either my plain wrapper function where I gain efficiency, or boost:function where I pay some runtime overhead but gain functor support.
Just hope as you said, 'delegate' can be included in the next release of the language.
I'm a little concerned that since they've included boost::function ,
they may think they've answered the need for delegates/closures. But
really, boost::function generates slow, complicated code for such a
simple concept. I find it very disappointing. And the absence of
operator == is a real limitation which convolutes a lot of code.
-Don. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: David Hill |
last post by:
Hello -
I am using a library that takes a function pointer as an argument. Is the code below not possible?
int library_func(void (*func)(int, short, void *));
I am trying to do this...
class Test {
|
by: Newsgroup - Ann |
last post by:
Gurus,
I have the following implementation of a member function:
class A
{
// ...
virtual double func(double v);
void caller(int i, int j, double (* callee)(double));
void foo() {caller(1, 2, func);
|
by: jon wayne |
last post by:
Hi
I'm a little confused here about the lifetime of a static pointer to
member function,
Say,
I declare,define & initialize a static ptr to mem function in the
header file of a class(the class is a helper Singleton class, and is
created & deleted as and when required) - Where does the static pointer
point to when every single instance of the class is deleted.
I presume it'll be dangling pointer- as the code seg to which it's
|
by: keepyourstupidspam |
last post by:
Hi,
I want to pass a function pointer that is a class member.
This is the fn I want to pass the function pointer into:
int Scheduler::Add(const unsigned long timeout, void* pFunction, void*
pParam)
|
by: WaterWalk |
last post by:
Hello. I thought I understood member function pointers, but in fact I
don't. Consider the following example:
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
| |
by: Tim Frink |
last post by:
Hi,
I'm experimenting with function pointers and found
two questions. Let's assume this code:
1 #include <iostream>
2 class A;
3
4 ////////////////////////////////////////////
5 class B
|
by: Immortal Nephi |
last post by:
I would like to design an object using class. How can this class
contain 10 member functions. Put 10 member functions into member
function pointer array.
One member function uses switch to call 10 member functions. Can
switch be replaced to member function pointer array?
Please provide me an example of source code to show smart pointer
inside class. Thanks....
|
by: Immortal_Nephi |
last post by:
I had a lot of research to see how function pointer works. Sometimes,
programmers choose switch keyword and function in each case block can
be called. Sometimes, they choose ordinary function pointer array
instead of switch.
They believe that ordinary function pointer is much faster than
switch. Think of one variable called selectFunction. selectFunction
variable can be the range of 0 through 1,000 or more.
Load selectFunction...
|
by: ghulands |
last post by:
I am having trouble implementing some function pointer stuff in c++
An object can register itself for many events
void addEventListener(CFObject *target, CFEventHandler callback,
uint8_t event);
so I declared a function pointer like
typedef void (CFObject::*CFEventHandler)(CFEvent *theEvent);
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look !
Part I. Meaning of...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed.
This is as boiled down as I can make it.
Here is my compilation command:
g++-12 -std=c++20 -Wnarrowing bit_field.cpp
Here is the code in...
| |
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own....
Now, this would greatly impact the work of software developers. The idea...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules.
He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms.
Adolph will...
|
by: TSSRALBI |
last post by:
Hello
I'm a network technician in training and I need your help.
I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs.
The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols.
I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |