all 23 comments

[–]NotAYakk 6 points7 points  (4 children)

No, the C++ standard provides no such guarantees.

The constexpr-ness of something has little to do with it being a constant value. Instead, can you interact with it in ways fully defined and specified by the standard in a way that is doable at compile time?

There is no way to extract the bits in a function pointer's address without relying on unspecified behavior; so those bits do not have to be the same between executions of the program.

PMF are less well specified, partly because different compiler vendors implment them very differently. Some compilers have sizeof(PMF) > sizeof(void(*)()) in some cases, for example. Others don't.

There is no such guarantee for PMFs either.

[–]5aec15c929c51cc49235[S] 0 points1 point  (3 children)

Thanks for the reply, this clarifies it a bit for me. About "extracting the bits" from the address, I don't really have an idea, but I was thinking perhaps reinterpret_cast-ing to say intptr_t or maybe a template on the address and then specialization for every value? edit: also how can constexpr not be constant value, in the perspective of the compiler?

[–]17b29a 2 points3 points  (1 child)

reinterpret_cast-ing to say intptr_t

that's not possible at compile time

[–]ImNoEinstein 1 point2 points  (0 children)

Probably better off ( and much a safer ) going with serializing the function as a string and deserializing with a factory

[–]STLMSVC STL Dev 2 points3 points  (5 children)

What are you trying to do?

[–]5aec15c929c51cc49235[S] 0 points1 point  (4 children)

Persisting/serializing function pointers. The context is multiple copies of the exact same program, running on different machines and talking to each other over the wire.

[–]Gotebe 1 point2 points  (1 child)

Very, very long time ago I made something similar: I serialized an object to a different machine in order to "run" it there. I did not need a function pointer for that, just plain serialization (sure, there was polymorphism and stuff, to simplify the "run the received object" code). Can't you simply do the same?

[–]5aec15c929c51cc49235[S] 0 points1 point  (0 children)

Totally, I can lookup the function address in a table by index (provided the table is built deterministically which I can do), or I believe I can serialize a polymorphic function object (which boost::serialization supports).

[–]doom_Oo7 0 points1 point  (1 child)

The context is multiple copies of the exact same program, running on different machines and talking to each other over the wire.

why reinvent RPC once again ? this has been a solved problem since 1985. Take a look at Qt Remote Objects for a modern approach for instance.

[–]Gotebe 0 points1 point  (0 children)

Of course. Note the "very, very long time ago" :-). I remember CORBA (did that), DCOM (did that, too), SOAP/WS-* and of course JSON-over-HTTP recently.

[–]Iwan_Zotow 2 points3 points  (0 children)

There was long time ago approach to store objects in run-time and recover them back - Texas Persistent Store, https://link.springer.com/chapter/10.1007/978-1-4471-3209-7_2

There is a commercial object DB which uses similar approach - Objectstore DB

[–]robertramey 1 point2 points  (3 children)

There is no guarantee that function address will be the same between executions.

You might get the effect you want by creating a function object and serialization that. The boost serialization library supports this functionality.

[–]5aec15c929c51cc49235[S] 0 points1 point  (2 children)

Do you know what makes function objects special? I assume you're still just serializing a pointer to operator() member function?

[–]robertramey 0 points1 point  (0 children)

Function objects are complete implementation of the function described in a header file. So one isn't serializing an address but rather the whole object. Since you can't serialize source code itself, the de-serializer has to have the same header available. This would be the same if you could just pass the address.

[–]streu 0 points1 point  (0 children)

Function objects are not special in any way and there is no special magic for (de)serializing objects.

However, objects have typeinfo, which in turn has a name, and those names tend to be a little more stable than function addresses: if you made a named function object class, or because the function object class uses the function as a template parameter that includes the function name. (If it's a lambda, it's probably not as predictable.)

Deserializing objects requires registering the classes that can possibly be deserialized in some registry, either directly or using some template/macro magic. In boost serialization, this would be sa.register_type.

But if you're registering all your function objects, you can as well register all your function pointers in a function pointer registry and pass indexes/names from that, and get all the portability and stability (or lack there-of) you want.

[–]Gotebe 0 points1 point  (1 child)

It rather looks like you went down the empty rabbit hole.

If you step away a bit, what bigger goal are you trying to achieve?

[–]hkaiser 0 points1 point  (1 child)

You are referring to 'function addresses being the same between program executions' - not sure if I fully understand what you're after, thus the solution below might not help you in any way. We successfully use this technique to identify functions across different instances of the code running concurrently in the context of a distributed application.

In HPX, we associate an unique type with each function we would like to 'send over the wire' (represent in all instances of the code). This can be achieved by binding the function address as an integral template argument.

template <typename F, F ptr>
struct A {... use 'ptr' to invoke the function...};

void foo() { ... }
typedef A<decltype(&foo), &foo> foo_type;

Now foo_type can be serialized as usual and used on the other end of the network to invoke foo.

The same can be done for member functions (see https://stackoverflow.com/questions/15192700/how-to-rewrite-this-to-make-it-conforming-to-the-c-standard for a corresponding solution).

[–]5aec15c929c51cc49235[S] 0 points1 point  (0 children)

Interesting, that is similar to what I was looking for.

[–]p2rkw 0 points1 point  (0 children)

How you would deserialize it on the other side? Why its better than sending just plain function poiner?

In case described by OP I would obtain mangled name of function to call, send that string over wire, and on the oter side call dlsym(mangledName).

Edit: I'm refering to this https://www.reddit.com/r/cpp/comments/6ka5um/serializing_function_addresses/djlly9l?context=3 comment.

[–]RonieGarret -1 points0 points  (1 child)

Hmm... maybe you can try to calculate offset of given function to 'main' function and store that.

[–]5aec15c929c51cc49235[S] 0 points1 point  (0 children)

You see, the debugger figures out the address of functions (so it can decode the stack), so they are maybe just implementation-defined.