Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ trying to get function address from a std::function

i'm trying to find the address of a function from a std::function.

The first solution was:

size_t getAddress(std::function<void (void)> function) {
    typedef void (fnType)(void);
    fnType ** fnPointer = function.target<fnType *>();
    return (size_t) *fnPointer;
}

But that only works for function with (void ()) signature, since i need for function that signature are (void (Type &)), i tried to do

template<typename T>
size_t getAddress(std::function<void (T &)> function) {
    typedef void (fnType)(T &);
    fnType ** fnPointer = function.target<fnType *>();
    return (size_t) *fnPointer;
}

And i get "Error - expected '(' for function-style cast or type construction"

Update: Is any way to capture member class address? for class members i'm using:

template<typename Clazz, typename Return, typename ...Arguments>
size_t getMemberAddress(std::function<Return (Clazz::*)(Arguments...)> & executor) {
    typedef Return (Clazz::*fnType)(Arguments...);
    fnType ** fnPointer = executor.template target<fnType *>();
    if (fnPointer != nullptr) {
        return (size_t) * fnPointer;
    }
    return 0;
}

Update: To capture lambda i'm using

template <typename Function>
struct function_traits
    : public function_traits<decltype(&Function::operator())> {
};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
    typedef ReturnType (*pointer)(Args...);
    typedef std::function<ReturnType(Args...)> function;
};

template <typename Function>
typename function_traits<Function>::function
to_function (Function & lambda) {
    return static_cast<typename function_traits<Function>::function>(lambda);
}

template <typename Lambda>
size_t getAddress(Lambda lambda) {
    auto function = new decltype(to_function(lambda))(to_function(lambda));
    void * func = static_cast<void *>(function);
    return (size_t)func;
}

std::cout << getAddress([] { std::cout << "Hello" << std::endl;}) << std::endl;
like image 774
Agustin Alvarez Avatar asked Aug 04 '13 04:08

Agustin Alvarez


People also ask

How do I find the address of a function pointer?

Address of a function in C or C++ We all know that code of every function resides in memory and so every function has an address like all others variables in the program. We can get the address of a function by just writing the function's name without parentheses. Please refer function pointer in C for details.

Can you copy std :: function?

You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.

What is std:: bind in c++?

std::bind takes a function as its first parameter and then that function's argument as its parameter. auto add_func = std::bind(&add, _1, _2); auto add_func = std::bind(&add, _1, _2); auto add_func = std::bind(&add, _1, _2);

Why use function pointers?

Function pointers can be useful when you want to create callback mechanism, and need to pass address of a function to another function. They can also be useful when you want to store an array of functions, to call dynamically for example.


2 Answers

You need to use the template keyword when you call target:

#include <functional>
#include <iostream>

template<typename T>
size_t getAddress(std::function<void (T &)> f) {
    typedef void (fnType)(T &);
    fnType ** fnPointer = f.template target<fnType*>();
    return (size_t) *fnPointer;
}

void foo(int& a) {
    a = 0;
}

int main() {
    std::function<void(int&)> f = &foo;
    std::cout << (size_t)&foo << std::endl << getAddress(f) << std::endl;
    return 0;
}

Hint: When you have problems with C++ syntax, I suggest you use clang++ to compile your code. If you play around with how your write the code it will usually point you in the write direction to fix the error (when it can figure out what you are doing).

I also suggest that you use variadic templates to make your function a bit more general:

template<typename T, typename... U>
size_t getAddress(std::function<T(U...)> f) {
    typedef T(fnType)(U...);
    fnType ** fnPointer = f.template target<fnType*>();
    return (size_t) *fnPointer;
}
like image 112
Robert Mason Avatar answered Oct 06 '22 00:10

Robert Mason


A std::function is just an object, albeit disguised as not-an-object. So, we can take the address of this object, and this is invariant across copies and such.

To get the pointer, we need a bit of casting. Eg given a function f1, we can print the implicit pointer by doing:

std::cout << "f1: " << *(long *)(char *)&f1 << std::endl;

What this does is:

  • takes the address of f1. f1 is itself a pointer to the function object, albeit disguised as a primitive
    • so this address is a pointer to the pointer to the function
    • what we want is the underlying pointer to the function
  • cast the pointer to pointer into a pointer to char
  • thence to a pointer to long
  • now, assuming that pointer sizes are longs, we can derefernce this pointer to long, and get the underlying address associated with the function object.

Given two std::function<void()>s f1 and f2, we can do things like:

std::cout << "f1: " << *(long *)(char *)&f1 << std::endl;
std::cout << "f2: " << *(long *)(char *)&f2 << std::endl;

std::function<void()> f1copy = f1;
std::cout << "\nafter copy f1 into f1copy:" << std::endl;
std::cout << "addresses of f1 and f1copy differ: " << &f1 << " " << &f1copy << std::endl;
std::cout << "but underlying pointers identical: " <<
    *(long *)(char *)&f1 << " " << *(long *)(char *)(&f1copy) << std::endl;

std::cout << "\n after assign f2 to f1copy" << std::endl;
f1copy = f2;
std::cout << "now the underlying pointer of f1copy matches f2's:" << std::endl;
std::cout <<
    *(long *)(char *)&f2 << " " << *(long *)(char *)&f1copy << std::endl;

Example output:

f1: 4439003784
f2: 4439003912

after copy f1 into f1copy:
addresses of f1 and f1copy differ: 0x7fff572ab970 0x7fff572ab910
but underlying pointers identical: 4439003784 4439003784

 after assign f2 to f1copy
now the underlying pointer of f1copy matches f2's:
4439003912 4439003912
like image 24
Hugh Perkins Avatar answered Oct 05 '22 23:10

Hugh Perkins