Amperage
Amperage

Reputation: 11

How to get a function name passed in parameters?

I've just found something as get the name of current function or get name of the caller, some variants to get or call the name as string.

What I want is to get the name of the function that I passed in arguments. Like this:

void Bar()
{
//do something
}

void Foo(void (*f)())
{
//this will output: Foo
std::cout << __FUNCTION__ << std::endl;

//How do I get the name passed to f? (in this case: Bar)
}

int main()
{
Foo(Bar);
return 0;
}

Thanks.

Edit: Here is an extremely near code for what I'm trying following the suggestion of @Jose.

    thread_local const char * m_last_function_called = "";
    #define register_function() {m_last_function_called = __FUNCTION__;}
    inline const char * get_last_function() { return m_last_function_called; }

//  const char * g_last_function_called = "";
//  #define register_function() { g_last_function_called = __FUNCTION__; }
//  inline const char * get_last_function() { return g_last_function_called; }

    void print_last_func()
    {
        static std::mutex sync_cout;
        std::lock_guard<std::mutex> l(sync_cout);
        std::cout << get_last_function() << std::endl;
    }

    bool interruptFooTimer = false;
    int FooTimer()
    {
        register_function();
        print_last_func();

        std::cout << "FooTimer.start" << std::endl;
        int t = 0;
        while(t<10)
        {
            if(interruptFooTimer==false)
            {
                sleep(1);
                t++;
                std::cout << "\tt=" << t << std::endl;
            }
            else
            {
                return -1;
            }
        }
        std::cout << "FooTimer.end" << std::endl;
        return 0;
    }

    void CallTrd(int (*f)())
    {
        std::thread TrdTemp(f);
        TrdTemp.detach();
        TrdTemp.~thread();
        print_last_func();
    }

int main()
{
    CallTrd(FooTimer);
    print_last_func();
    int c = 0;
    while(c<15)
    {
        if(c==7) {interruptFooTimer=true;}
        sleep(1);
        c++;
        std::cout << "c=" << c << std::endl;
        print_last_func();
    }
    return 0;
}

Observe that I call print_last_func() in different moments and all get the same value that was initialized in the variable. This sample code calls a thread without using join() because I can't wait for the thread to finish and also implement the detach() and ~thread to finish my program without any exception. The interruptFooTimer I'm using to safely "terminate" my thread. What am I missing to get global the value acquired in register_function??

Upvotes: 1

Views: 3328

Answers (4)

Jts
Jts

Reputation: 3527

I don't know why you wanna do it, but I hope it's for debugging purpose. Obviously the easiest path is to pass the __FUNCTION__ as an argument as pointed out. But in my point of view, there's a better approach.

You could have for example, a global variable:

thread_local const char * g_last_function_called = ""; 

#define register_function() { g_last_function_called = __FUNCTION__; }
inline const char * get_last_function() { return g_last_function_called; }

void Bar()
{
    register_function() 
}

void Foo(void (*f)())
{
    std::cout << get_last_function() << std::endl;
}

void my_func_that_doesnt_accept_nulls(CClass * p) 
{
     if (p == nullptr)
     {
        std::cout << " function" << get_last_function();
        std::cout << "passed a bad pointer, fix it" << std::endl;
        return;
     }
}

Of course, this will not give you the right result in multi-thread, but you can probably fix that using a thread_local const char * g_last_function_called = "" variable.

The reason why I like this method is because all you have to do to remove it from your project is just a simple "find and replace" of register_function(), and since it uses plain pointers, there's no way it can slow your program at all.

Edit: this is how I'm testing the code

void print_last_func()
{
    static std::mutex sync_cout;
    std::lock_guard<std::mutex> l(sync_cout);
    std::cout << get_last_function() << std::endl;
}

void HelloWorld1()
{
    register_function();
    print_last_func();
}

void HelloWorld2()
{
    register_function();
    print_last_func();
}

int main()
{
    register_function();
    std::thread t1(HelloWorld1);
    std::thread t2(HelloWorld2);
    print_last_func();
    t1.join();
    t2.join();
    return 0;
}

I get: HelloWorld1, HelloWorld2, and main

Upvotes: 0

Mohamad Elghawi
Mohamad Elghawi

Reputation: 2124

As others have already noted, you cannot do this directly.

First of all I would use std::function instead of a raw function pointer and std::string to hold the function's name.

I would also wrap these up like this:

template<class T>
struct Functor
{
    std::function<T> functor_;
    std::string name_;

    Functor(const std::function<T>& functor, const std::string& name)
        : functor_(functor)
        , name_(name)
    {}
};

You can then use it like so:

void Bar()
{
    // do something
}

void Foo(const Functor<void()>& functor)
{
}

int main() 
{
    Functor<void()> f(std::bind(Bar), "Bar");
    Foo(f);
    return 0;
}

You can also use a macro to make things easier for you.

#define FUNCTOR(t, x, ...) Functor<t>(std::bind(&x, __VA_ARGS__), #x)

Which can be used like this:

int main() 
{
    auto f = FUNCTOR(void(), Bar);
    return 0;
}

Note that if you take this approach that the function name might not be the same as what using __FUNCTION__ yields.

Upvotes: 0

Anatolijs Gorbunovs
Anatolijs Gorbunovs

Reputation: 69

Use a helper macro:

#define Foo(x) FooHelper(#x, x)
void FooHelper(const char *f_name, void (*f)())
{
    cout << f_name;
}

Upvotes: 0

Zbynek Vyskovsky - kvr000
Zbynek Vyskovsky - kvr000

Reputation: 18825

You cannot. __FUNCTION__ is expanded by compiler during the compilation time. You cannot get this information in runtime.

Upvotes: 1

Related Questions