Ottieni il puntatore alla funzione da std::function quando usi std::bind

Ottieni il puntatore alla funzione da std::function quando usi std::bind

Questo è del tutto impossibile. L'intero motivo per cui std::function esiste è che i puntatori di funzione fanno schifo in modo orribile e non dovrebbero mai, mai, essere usati da nessuno, mai più, ad eccezione delle anime condannate che portano gli stendardi infuocati dell'inferno C interoperabilità, perché non possono gestire funzioni con stato.

Un std::function<void()> non può, nel caso generale, essere convertito in un void(*)() . L'unico motivo per cui funziona nel primo esempio è perché succede essere un void(*)() originariamente.


Questo può essere ottenuto usando una piccola meta-programmazione del modello. Di recente l'ho utilizzato mentre scrivevo un wrapper C++ generico attorno a OpenGL GLUT (che dipende dai puntatori alla funzione di callback). L'approccio:

  1. Crea un'istanza di un tipo di modello singleton.
  2. Memorizza la tua std::function come membro dell'istanza singleton
  3. Richiama la tua std::function tramite una funzione membro statica (le funzioni membro statiche e le funzioni libere hanno lo stesso tipo, quindi la funzione "invoke" può essere utilizzata come puntatore a funzione libera)

Testato in C++11 su 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;
}

Non puoi ottenere un puntatore a funzione su un std::function , poiché potrebbe non essercene nemmeno uno. Potrebbe essere un puntatore a funzione membro invece, o un oggetto che implementa operator() .