c++:std::function returns 空指针实例的目标

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

编译如下代码:

#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;
}

但执行时打印:

5!
nullptr

我想了解为什么 target 返回一个空指针,而不是指向函数“say”的指针。

注意:它为 c++ 编译到 c++14,对于 c++17 以后,编译失败并出现错误(这对我来说很神秘):

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);
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在 VS2017 上重现了它,看起来像 target 方法 returns 一个 指向指针 的指针(如返回指向存储的实际函数指针的指针在对象中),并相应地期望其模板类型参数。这是一个有效的修改示例:

#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;
}

确认 target 通过 运行 返回指向实际函数指针的指针:

#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;
}

这产生了以下输出:

5!
booooo