c ++: цель экземпляра std :: function возвращает нулевой указатель - PullRequest
0 голосов
/ 01 августа 2020

Скомпилирован следующий код:

#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 вернул пустой ptr, а не указатель на функцию "say".

примечание: он компилируется для c ++ до c ++ 14, для c ++ 17 и далее компиляция завершается с ошибкой (для меня это crypti c):

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

1 Ответ

3 голосов
/ 01 августа 2020

Воспроизведено на VS2017, похоже, что метод target возвращает указатель на указатель (как при возврате указателя на фактический указатель функции, хранящийся в объекте), и, соответственно, ожидает его аргумент типа шаблона . Вот модифицированный пример, который работает:

#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
...