bdahl
bdahl

Reputation: 57

C++ 11 get pointer of a std::function

I want to store and identify std::function objects in a std::map. To identify I want to use the std::function::target. I can't get the pointer from std::function::target if I use std::bind to bind to a member function from a class.

#include <functional>
#include <iostream>


using namespace std;
void normal_fun(int a)
{
    std::cout << "hello\n"<<a;
}

class testclass
{
public:
    int b;
    void mytest(int a)
    {
        b = a;
    }
};

uintptr_t getFuncAddress(std::function<void(int)> &f)
{
    uintptr_t returnAddress = reinterpret_cast<uintptr_t>(f.target<void(*)(int)>());
    return returnAddress;
}

int main()
{

    testclass c;
    std::function<void(int)> f1 = bind(&testclass::mytest,&c, placeholders::_1);
    std::function<void(int)> f2 = normal_fun;
    auto addrF1 = getFuncAddress(f1);
    auto addrF2 = getFuncAddress(f2);
}

How can I achieve what I want to do?

Upvotes: 2

Views: 3069

Answers (4)

eerorika
eerorika

Reputation: 238351

f.target<void(*)(int)>

Is wrong, because the type returned by bind is not void(*)(int), so the target will never return a non-null pointer. Bind does not return a function pointer. It returns some object of implementation specified type.

The type can be acquired with decltype. This is a bit perverse, but should be correct:

f.target<decltype(bind(
  &testclass::mytest,
  (testclass*)nullptr,
  placeholders::_1)
)>

but i have the Problem that i didn't know in getFuncAddress if i have testclass or myOtherClass or someone else Class

You can only use std::function::target if you know the type of the wrapped object. If the number of choices is limited, then you can try to get the target with each type until non-null is returned. For an arbitrary unknown type, std::function::target can not be of any use for you.


I want to store and identify std::function objects in a std::map

I think you will have to use some external key, that cannot be extracted from the std::function. This means that if you wish to prevent duplicates, you also need an external method of guaranteeing a unique mapping from key to the function.

Upvotes: 0

Jonathan Wakely
Jonathan Wakely

Reputation: 171293

The point of std::function is to give a uniform interface and type for callable objects that meet a given signature. You are expecting it to also provide a uniform key for sorting, but it doesn't do that. There is no way to sort function pointers and arbitrary function objects and callables returned by std::bind. They are completely different things, and comparing them doesn't make sense. All std::function allows you to do is store them and call them.

If you need a sorting mechanism you'll have to invent something yourself, you won't get it from std::function.

Upvotes: 2

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20141

I want to store and identify std::function objects in a std::map.

I assume, you want to identify std::function objects (e.g. to call or delete them selectively). In such situations, I use an additional key e.g. a simple unsigned. A global function may be used:

typedef unsigned Key;

Key genId()
{
  static Key id = 0;
  return ++id;
}

Now, the std::function objects can be paired with this key. The API may grant that access to paired std::function objects can be done using the key exclusively.

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

A std::function is not a function pointer. It is not even a pointer.

If you know what type is stored in a std::function, you can get a pointer to what it stores. Note that the pointer here is not the function pointer, but a pointer to the function pointer.

If you do not know what type it stores, you cannot.

If you want < or == or hash (etc), std::function does not provide this for you. It type erases (), copy, move, destruction, typeid, and cast-back-to-original.

You can use type erasure techniques to augment a std::function with those operations; note that type erasure on binary operations is a touch trickier than type erasure is in general.

Type erasing something shouldn't be your first go-to when solving a problem, but it will solve your problem. There are articles on type erasure in SO documentation for C++. This isn't a beginner subject.

Odds are your underlying problem can be solved in a much simpler way.

In any case, using the type returned from target to order is not a great idea, as it is a pointer to a possibly automatic storage object, or possibly heap storage object; the two of which are going to have significantly different invalidation rules under innocuous operations (like move). A SBO (small buffer optimization) target is going to move with the instance of the std::function, while a heap-allocated one is likely to stay with the state the std::function moves around under std::move-like operations. This is a real mess.

Upvotes: 2

Related Questions