3

I know that I can create method pointers, and I know that they are generally different than function pointers. Converting between them is not allowed. Method pointers can contain lots of data about how to adjust this pointer and so on.

I would like to know how to get actual address of code that is executing given method. This address will not be deferenced in any way, but will be used as identifier of type to which given method belongs - something a bit like RTTI, with advantage of being insensitive to library-boundaries, as this code is available in only one unit usually.

EDIT:

Why i don't add some getType() method returning object's type?

Because I want to be able to use in this manner not only classes created by me. What I am trying to do is basically my implementation ofvariant class, that would accept basically everything, provided specialization of void* getVariantId() for given type exists.

So then i could write:

template <typename T>
class getTypeId{
};

class foo{
    public:
    void bar();
};

// getTypeId declared but not defined for generic type T earlier...
template <>
class getTypeId<foo>{
    static void* get<foo>(){
        return &foo::bar;
    }
};

void doSomething(myVariant var);

int main(int argc, char* argv[]){
     foo f;
     myVariant var = myVariant::fromType<foo*>(&f);
     doSomething(f);
}

void doSomething(myVariant var){
    foo* f = var.toType<foo*>(); // Returns foo object from main
    int* i = var.toType<int*>(); // returns null, as var is not int* in my example.
}

The idea is that fromType is using getTypeId to obtain type's representing value, and stronig it along with object's pointer casted to void*. toType on the other hand is comparing value got from `getTypeId::get and one stored in object - if it matches then internally kept object pointer is reinterpreted back to original type and returned.

Beauty of this solution is, that even if there is some shared library X, that define type x, then libraries Y and Z, that separately use library X would agree on type x being the same (eg. in case variant create in Y is passed to Z), cause address on X::method remains the same. As creator of Y or Z library (but NOT X!!!), I don't need to ensure X lib has RTTI enabled or even is aware of myVariant existence, yet type x is still fully myVariant compatible.

EDIT2:

I see by now that there is no implementation-independent way to get this done. However I think that this is quirk of not-usually-needed, and therefore not-existing feature, rather than feature that is impossible to create. I think I still haven't made it clear what I wanted to acheive and how I was plannig to do so. So:

  • By libraries I mean here shared libraries (.dll, .so and so on).

  • Every method that is not pure virtual (means every method that is defined) must have implementation. This implementation behaves as a function that accepts one additional parameter this - virtual functions are different only on caller side. Let's take class X and it's method X::foo as an example. This method is bound only to X type, even if type Y inherits it, this method remains X::foo and therefore it is enought to identify type X. Overriding virtual method or covering method in child class Xchild is de-facto defining new method Xchild::foo with new address. Then you might use Xchild::foo to represent Xchild, but not X.

  • If type X (all it's methods to be accurate) are defined in library libX, and libY and libZ are both using libX (but not knowing aobut each other), and definig for their own purposes getTypeId using first method in X to represent it (note that this doesn't impose anything on libX developer), then they are in agreement about what type X is. If application developer uses libY to get variant and pass it to libZ, both will recognize mentioned type properly.

  • I am NOT trying to develop type-casting-variant - variant saved as X can be read only as X, even if actual pointer passed to myVariant was Xchild. I am not interested in getting type of topmost class for given instance - just class that was used to create variant.

Matt
  • 22,721
  • 17
  • 71
  • 112
j_kubik
  • 6,062
  • 1
  • 23
  • 42
  • 1
    There's no portable way to do what you want. – Jonathan Grynspan Nov 07 '11 at 20:36
  • If for some reason you can't use true RTTI, why not just define a virtual method that returns a static value that's different for each defined class? – Mark Ransom Nov 07 '11 at 20:39
  • Because i want to use it with any class, not only written by me. – j_kubik Nov 07 '11 at 21:18
  • "This method is bound only to X type, even if type Y inherits it, this method remains X::foo and therefore it is enought to identify type X." Which means that if you're passed a `Y`, any attempt to identify it's type via the `foo` function will conclude falsely that it is an `X`. So your type identification scheme does not correctly identify the type. – Nicol Bolas Nov 07 '11 at 23:58
  • "note that this doesn't impose anything on libX developer" Except that it does. You require type `X` to have some specific member function name/signature that your `getTypeId` function looks for. Your method does not even meet your own requirements, even if you could get the function pointer for a method. – Nicol Bolas Nov 08 '11 at 00:01
  • @Nicol Bolas: I assume that libY and libZ developers know exactly X declaration, so they can both use first acceptable method form X declaration (as only numeric value of addres is important, signature doesn't matter). Then they both provide their own, library-specific getTypeId specializations, but since they are using the same method (first one), returned identifier is the same, thus keeping type identity between thode libraries. Whole point is that actual method used is not specified by generic getTypeId template function, but is determined by X type and a few rules. – j_kubik Nov 08 '11 at 01:09

3 Answers3

3

The C++ FAQ Lite devotes an entire section to Pointers to Member Functions.

Two answers in particular state why what you are trying to do cannot be done (at least, not in a portable way):

  • Pointer-to-member-function is a different animal:

C++ introduces a new type of pointer, called a pointer-to-member, which can be invoked only by providing an object. Do not attempt to "cast" a pointer-to-member-function into a pointer-to-function; the result is undefined and probably disastrous. E.g., a pointer-to-member-function is not required to contain the machine address of the appropriate function.

  • Pointer-to-member-functions can point at virtual functions:

A pointer to a member function might be a data structure rather than a single pointer. Think about it: if it's pointing at a virtual function, it might not actually be pointing at a statically resolvable pile of code, so it might not even be a normal address.

Gnawme
  • 2,321
  • 1
  • 15
  • 21
  • What if what I want is exactly that? Pointer to "statically resolvable pile of code"? Since I want to always specifiy which code exactly I mean and do it only for those that are resolvable - say X::foo and not It's oveerides? – j_kubik Nov 07 '11 at 23:04
  • You would have to examine your compiler's implementation of pointer-to-member-function; it should store stuff like virtual/nonvirtual, where its vtable is, the offset from `this`, etc. Even then, as my first point notes, the pointer-to-member-function is not **required** to contain the machine address of the appropriate function. – Gnawme Nov 07 '11 at 23:22
  • "the pointer-to-member-function is not required to contain the machine address of the appropriate function" - but I require to get this address int my (void*) variable ;) How to do this is not that important - anyway I see there is virtually no way to do this, so now I am treating it rather as small mind exercise rather than practical question. – j_kubik Nov 07 '11 at 23:42
  • I am accepting this as closest to answer to my question. I guess I will not progress anymore on this, and so my project is hereby dead ;) – j_kubik Nov 10 '11 at 17:06
  • Oh, well; on to the next project! :-) – Gnawme Nov 10 '11 at 17:10
1

I would like to know how to get actual address of code that is executing given method. This address will not be deferenced in any way, but will be used as identifier of type to which given method belongs - something a bit like RTTI, with advantage of being insensitive to library-boundaries, as this code is available in only one unit usually.

RTTI is not limited by translation units. The only limitations of RTTI around libraries is the DLL boundary, where one DLL would expose a function that returns a derived class. And I'm not 100% sure, but so long as the DLL and executable are all built with the same compiler (and share static libraries), I think it will still work.

In any case, what you're asking for cannot be done. A member pointer is not a pointer, and there is no portable way to get an actual function pointer to a member function.

And even if it could, it wouldn't give you a unique identifier for a type. After all, if a class does not override a function, or if the function isn't virtual, then the address of that member function will be the same for each class that uses it. It will only change if the function is virtual and the class overrides it.

There's no way to make a unique type identifier out of that.

It seems to me that what you want is Boost.Any, which uses RTTI internally to prevent you from casting to the wrong type.


The places where your plan breaks down

You are proposing a getTypeId function which would be implemented like this:

template<typename T>
SomeIdentifierTypedef getTypeId(const T &x)
{
  void *ptr = GetMemberFuncPtr<T>(x, &x::foo);
  return FindIdFromPtr(ptr);
}

This requires the existence of GetMemberFuncPtr, which takes an member pointer and an object, and gets the actual function pointer of that member. This function is intended to return a unique value for every type it receives.

OK, now consider what you have said:

Let's take class X and it's method X::foo as an example. This method is bound only to X type, even if type Y inherits it, this method remains X::foo and therefore it is enought to identify type X.

If Y::foo and X::foo are the same member function, then naturally they have the same function pointer. Therefore, getTypeId(Y()) == getTypeId(X()). That violates the stated objective of getTypeId. You want it to return a different value if the type is Y than if it is X.

If type X (all it's methods to be accurate) are defined in library libX, and libY and libZ are both using libX (but not knowing aobut each other), and definig for their own purposes getTypeId using first method in X to represent it (note that this doesn't impose anything on libX developer), then they are in agreement about what type X is. If application developer uses libY to get variant and pass it to libZ, both will recognize mentioned type properly.

This cannot work for two reasons. First, notice that my implementation of getTypeId has ::foo in it. That's because there is no way to talk about an arbitrary method of a class. You have to use a name (and likely a full-fledged signature if you want to be sure) in order to talk about a particular function. You can't just say "get me some function from this type." You have to pick one.

Which means you have to pick the same one for all possible template types of getTypeId. Therefore, all classes that you use getTypeId for must implement the same function.

Oh, you could try to specialize it for certain types. But that runs headlong into the second problem.

Shared libraries do not share functions, unless they are explicitly shared. You cannot share X::foo. The only way for libX to pass libY a class that libY does not have a full and separate definition for is if the class is hidden in some way. So either it's an opaque pointer (void*), in which case you can't even get member functions to it. Or it is a derived class from a definition that both libX and libY have.

That is, there is some (possibly abstract) class base, which both libX and libY were compiled against. libX creates X which is derived from base, and there is some function that libX exposes which returns an X as a base *.

In this case, specialization doesn't help, because only libX has access to the specialization getTypeId<X>. The only way for it to work would be if the specialization were for getTypeId<base>. But then we run back into the problem of what if the user doesn't override the virtual function? Then we think it's still a base.

Even if the test function is a pure-virtual function, that won't help. This is because libX could have a Y which is derived from X which is derived from base. X may have implemented the function, but Y didn't override it. Therefore getTypeId(x) == getTypeId(y) again.

Your idea cannot work.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Yes - I am looking for something like Boost.Any, but without relying on RTTI, for example because many external libraries is compiled without it to make executables smaller. I still think that it is possible - it is true that methods are derived to child classes, but it is me who decide which method i use to represent class (by definig `getTypeId` for this class) - simple rule stating X::bar represents X only if it was declared there, and not in parent class fixes the problem. It is also not about type-casting inside variant - if variant was created with type X, it can only read type X. – j_kubik Nov 07 '11 at 22:23
  • @j_kubik: Your own post said that you didn't want to define a specific method, because you wanted to be able to use this with other people's classes without imposing restrictions on them. And as I pointed out, even if you could use a function pointer to work as a type id, C++ does not allow you to get a function pointer to a member function. Not in a portable way. – Nicol Bolas Nov 07 '11 at 22:29
  • @j_kubik: The only reason you would be unable to get RTTI for a class (unless you are downloading static libraries rather than building them yourself, which is not wise) is if we are talking about types hidden across the DLL boundary. And if we are, then your code itself doesn't have access to the actual class that the DLL can return. Therefore, it cannot _know_ what method the user may or may not have overridden in his class hierarchy. Even if the method is pure-virtual, it could only point to the _first_ class that they overrode it in, not the current class. – Nicol Bolas Nov 07 '11 at 22:31
  • "The only way for libX to pass libY a class that libY does not have a full and separate definition for is if the class is hidden in some way." - How about libX coming with X.h that contains class declaration (#include'd in libY)- thus making it available to libY, and containin method's definitions only in libX, and therefore not contained but available in libY? As far as I know this is standard approach, isn't it? – j_kubik Nov 08 '11 at 00:56
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4792/discussion-between-nicol-bolas-and-j-kubik) – Nicol Bolas Nov 08 '11 at 02:12
0

If you only want to deduce types from each other (so basically create custom RTTI) you could just create a method returning some sort of type identifier.

class MyFirst
{
public:
    inline virtual string GetType() { return "Myfirst"; }
};

Then overload GetType() function for every class you create.

This is usually the simplest method (apart, of course, from dynamic_cast). If you REALLY want to get the type of object from virtual call, you could set a static flag denoting last type used, or return it from every function which said object has.

If you could write HOW you really wanted to "get actual address of code that is executing given method", your question would certainly be clearer.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • BTW `inline static virtual`? Now that's something you don't see very often ;) – j_kubik Jun 21 '13 at 22:57
  • @j_kubik oh god I must have derped really hard when I wrote this. In fact, it was my 4th SO answer. I feel deeply ashamed of that time, but at least I think the improvement is quite big :) – Bartek Banachewicz Jun 22 '13 at 11:51