Search code examples
c++functionfunction-pointers

c++ : target of instance of std::function returns null pointer


The following code compiled:

#include <iostream>
#include <functional>

typedef void (*f_type) (int a);

void say(int a)
{
    std::cout << a << "!" << std::endl;
}

int main()
{

    int a=5;

    say(a);

    std::function<void(int)> fn{say};
    f_type fn_pointer = fn.target<void(int)>();
    
    if(fn_pointer)
        fn_pointer(a);
    else
        std::cout << "null ptr" << std::endl;

    return 0;
}

but when executed prints:

5!
nullptr

I would like to understand why target returned an empty ptr, and not a pointer to the function "say".

note : it compiles for c++ up to c++14, for c++17 onward, compilation fails with error (which is cryptic to me):

In file included from /usr/include/c++/7/functional:58:0,
                 from main.cpp:11:
/usr/include/c++/7/bits/std_function.h: In instantiation of ‘_Functor* std::function<_Res(_ArgTypes ...)>::target() [with _Functor = void(int); _Res = void; _ArgTypes = {int}]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',28)">main.cpp:28:46</span>:   required from here
/usr/include/c++/7/bits/std_function.h:733:9: error: invalid use of const_cast with type ‘void (*)(int)’, which is a pointer or reference to a function type
  return const_cast<_Functor*>(__func);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Solution

  • Reproduced it on VS2017, seems like the target method returns a pointer to pointer (as in returning a pointer to the actual function pointer stored in the object), and expecting its template type argument accordingly. Here is a modified example that works:

    #include <iostream>
    #include <functional>
    
    typedef void(*f_type) (int a);
    
    void say(int a)
    {
        std::cout << a << "!" << std::endl;
    }
    
    int main()
    {
    
        int a = 5;
    
        say(a);
    
        std::function<void(int)> fn{say};
        f_type* fn_pointer = fn.target<void(*)(int)>();
    
        if (fn_pointer)
            (*fn_pointer)(a);
        else
            std::cout << "null ptr" << std::endl;
    
        return 0;
    }
    

    Confirmed target returning a pointer to the actual function pointer by running the following:

    #include <iostream>
    #include <functional>
    
    typedef void(*f_type) (int a);
    
    void say(int a)
    {
        std::cout << a << "!" << std::endl;
    }
    
    void say_boo(int a)
    {
        std::cout << "booooo" << std::endl;
    }
    
    int main()
    {
        int a = 5;
        std::function<void(int)> fn{say};
        f_type* fn_pointer = fn.target<void(*)(int)>();
        (*fn_pointer)(a);
        fn = say_boo;
        (*fn_pointer)(a);
        return 0;
    }
    

    This produced the following output:

    5!
    booooo