Получить указатель на функцию из std :: function при использовании std :: bind

Я пытаюсь использоватьstd::function в сочетании сstd::bindно у меня есть некоторые проблемы.

Это работает:

#include <functional>
#include <iostream>

void print() {
    std::cout << 2;
}

int main() {
    std::function<void ()> foo = print;
    (*foo.target<void (*)()>())(); //prints 3
}

Это вылетает на второй строкеmain:

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() {
    std::function<void ()> foo = std::bind (print, 2);
    (*foo.target<void (*)()>())();
}

Я действительно держуstd::function<void ()> и должны иметь возможность вернуть функцию; не просто назвать это. Я ожидаю, что использование будет примерно таким:

#include <functional>
#include <iostream>

void print (int i) {
    std::cout << i;
}

int main() {
    Container c (std::bind (print, 2));

    //I would expect the original
    c.func() (3); //prints 3

    if (c.func() == print) /* this is what I'm mostly getting at */
}

Есть ли способ получить оригинальную функцию, чтобы вернуть его, или альтернативу? Это также противоречит типу возвращаемого значения, так какvoid (*)() очень хорошо соответствует связанной подписи.

 Puppy07 июн. 2012 г., 21:59
@chris: весь смысл хранения универсальной функции. Сравнение общих функций становитсяvery хитрый, и это только верхушка айсберга.
 R. Martinho Fernandes07 июн. 2012 г., 21:46
Это просто невозможно: нет функции сvoid() подпись в вашем коде. Если бы это было возможно, нам бы не понадобилосьstd::function.
 chris07 июн. 2012 г., 22:00
@DeadMG, ну, я бы не стал в это разбираться. Это не слишком важная особенность моего класса, но это приятно иметь. Я всегда могу сохранить отдельную переменную, если мне нужно.
 chris07 июн. 2012 г., 21:48
@ R.MartinhoFernandes, это была хорошая уловка для хранения универсальной функции, но, кажется, только вызов ее работает.

Ответы на вопрос(3)

Решение Вопроса

std::function существует то, что указатели функций ужасно сосут и никогда не должны использоваться кем-либо, никогда, кроме обреченных душ, несущихthe Burning Standards of Hell C взаимодействия, потому что они не могут обрабатывать функции с состоянием.

std::function<void()> в общем случае не может быть преобразован вvoid(*)(), Единственная причина, по которой это работает в первом примере, заключается в том, чтоhappens бытьvoid(*)() первоначально.

 08 июн. 2012 г., 03:40
@DavidRodriguez: ну почему бы просто ... использовать шаблон как нормальный человек?
 chris07 июн. 2012 г., 21:52
Полагаю, тогда мне просто придется забыть о сравнении, спасибо.
 07 июн. 2012 г., 22:12
function pointers suck... только так же, какint отстой, или необработанные указатели ... это блоки низкого уровня, на которых строятся конструкции более высокого уровня. Без сырых указателей и int у тебя бы не былоstd::stringбез указателей функций у тебя бы не былоstd::function...
 08 июн. 2012 г., 03:21
@ Дэвид: Не совсем. Вы можете реализоватьstd::function без каких-либо знаний функциональных указателей.
 08 июн. 2012 г., 03:29
@DeadMG: Вы хотите проиллюстрировать нас? О, ты имеешь в виду с лямбдами? Если это так, рассмотримboost::bind а такжеboost::function в компиляторе C ++ 03 или в любой библиотеке сигналов (sigc ++, boost :: сигналы, сигналы Qt) или у любого пользователя компиляторов Sun или HP, у которых пока нет поддержки лямбды ...

вания. Недавно я использовал это для написания универсальной оболочки C ++ для OpenGL GLUT (которая зависит от указателей на функции обратного вызова). Подход:

Instantiate an instance of a singleton template type. Store your std::function as a member of to the singleton instance Invoke your std::function through a static member function (static member functions and free functions have the same type, so the "invoke" function can be used as a free function pointer)

Протестировано подC ++ 11 на GCC 4.8.

#include <unistd.h>
#include <thread>
#include <chrono>
#include <mutex>
#include <functional>
#include <iostream>
#include <cmath>

template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
struct fun_ptr_helper
{
public:
    typedef std::function<_Res(_ArgTypes...)> function_type;

    static void bind(function_type&& f)
    { instance().fn_.swap(f); }

    static void bind(const function_type& f)
    { instance().fn_=f; }

    static _Res invoke(_ArgTypes... args)
    { return instance().fn_(args...); }

    typedef decltype(&fun_ptr_helper::invoke) pointer_type;
    static pointer_type ptr()
    { return &invoke; }

private:
    static fun_ptr_helper& instance()
    {
        static fun_ptr_helper inst_;
        return inst_;
    }

    fun_ptr_helper() {}

    function_type fn_;
};

template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type
get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f)
{
    fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f);
    return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr();
}

template<typename T>
std::function<typename std::enable_if<std::is_function<T>::value, T>::type>
make_function(T *t)
{
    return {t};
}

int main()
{
    std::cout << (void*)get_fn_ptr<0>(make_function(::sin))<<std::endl;
    return 0;
}
 13 февр. 2018 г., 14:16
Это решение не работает с многопоточностью, когда несколько потоков устанавливаютstd::function синглтон класса.
 24 окт. 2016 г., 16:10
Я сделал одну незначительную модификацию этого решения, которая заключается в добавлении имени типа для уникального идентификатора. В паре сstd::enable_if а такжеstd::is_literal это позволяет мне использовать перечисления или другие идентификаторы литерального типа в качестве уникального идентификатора, дополнительно определяя уникальность и предотвращая коллизии (за счет того, что этот вспомогательный код становится немного более многословным).

function pointer изstd::function, так как может даже не быть. Это может бытьmember function pointer вместо илиobject который реализуетoperator().

Ваш ответ на вопрос