Pass class method as void function pointer (C++11)










0















I have an object which needs to interface with an existing C api to register an in interrupt (void function taking no arguments). I can attach the interrupt to the function function(). However, I want to be able to pass in arguments to the function, but that would change the function signature. I thought a way around that would be to create an object to store the parameters (and modify them as necessary), and then pass in a method (or similar). However, I haven't been able to figure out how to do that.



I've tried passing in a lambda as [=]() std::cout << "a: " << a << "n"; , but it turns out lambdas with a capture can't be converted to function pointers. I've also tried a templated method (since it would get instantiated at compile time), but couldn't get it to work. I've seen some posts on SO talking about std::bind and std::function, but they often warn about virtual function overhead, which I'd like to avoid on an embedded platform for an ISR.



What is the best way to convert a paramterized function to a void(*)()?



#include <iostream>

void function()
std::cout << "Hello World!n";


void attach_interrupt(void(*fn)())
fn();


class A
int a;

public:
A(int a) : a(a)
attach_interrupt(function); // This works as expected
// attach_interrupt(method); // How do I make this work?
// attach_interrupt(method2<a>);


void method()
// something requiring a and b
std::cout << "a: " << a << "n";


template<int a>
void method2()
std::cout << "a: " << a << "n";

;

int main()

const int PIN_1 = 0;
const int PIN_2 = 1;
const int PIN_3 = 2;

A foo(PIN_1);
A bar(PIN_2);
A baz(PIN_3);

return 0;



EDIT: My solution, inspired by the selected answer:



#include <iostream>

void attach_interrupt(int pin, void(*fn)())
fn();


// Free function, which works as an ISR
template <unsigned int IRQ, unsigned int IRQ2>
static void irqHandler()

std::cout << "IRQ: " << IRQ << "n";
std::cout << "IRQ2: " << IRQ2 << "n";
;

template <unsigned int PIN_1, unsigned int PIN_2>
class Handler
private:

public:
Handler()
void(*irq)() = &irqHandler<PIN_1, PIN_2>;
attach_interrupt(0, irq);
attach_interrupt(0, &handler_2);


// static member function can have its address taken, also works as ISR
static void handler_2()
std::cout << "PIN_1: " << PIN_1 << "n";
std::cout << "PIN_2: " << PIN_2 << "n";

;

Handler<1, 2> a;
Handler<2, 3> b;

int main()

return 0;










share|improve this question
























  • You won't get around std::bind().

    – Swordfish
    Nov 15 '18 at 0:43






  • 1





    The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

    – user10605163
    Nov 15 '18 at 0:49
















0















I have an object which needs to interface with an existing C api to register an in interrupt (void function taking no arguments). I can attach the interrupt to the function function(). However, I want to be able to pass in arguments to the function, but that would change the function signature. I thought a way around that would be to create an object to store the parameters (and modify them as necessary), and then pass in a method (or similar). However, I haven't been able to figure out how to do that.



I've tried passing in a lambda as [=]() std::cout << "a: " << a << "n"; , but it turns out lambdas with a capture can't be converted to function pointers. I've also tried a templated method (since it would get instantiated at compile time), but couldn't get it to work. I've seen some posts on SO talking about std::bind and std::function, but they often warn about virtual function overhead, which I'd like to avoid on an embedded platform for an ISR.



What is the best way to convert a paramterized function to a void(*)()?



#include <iostream>

void function()
std::cout << "Hello World!n";


void attach_interrupt(void(*fn)())
fn();


class A
int a;

public:
A(int a) : a(a)
attach_interrupt(function); // This works as expected
// attach_interrupt(method); // How do I make this work?
// attach_interrupt(method2<a>);


void method()
// something requiring a and b
std::cout << "a: " << a << "n";


template<int a>
void method2()
std::cout << "a: " << a << "n";

;

int main()

const int PIN_1 = 0;
const int PIN_2 = 1;
const int PIN_3 = 2;

A foo(PIN_1);
A bar(PIN_2);
A baz(PIN_3);

return 0;



EDIT: My solution, inspired by the selected answer:



#include <iostream>

void attach_interrupt(int pin, void(*fn)())
fn();


// Free function, which works as an ISR
template <unsigned int IRQ, unsigned int IRQ2>
static void irqHandler()

std::cout << "IRQ: " << IRQ << "n";
std::cout << "IRQ2: " << IRQ2 << "n";
;

template <unsigned int PIN_1, unsigned int PIN_2>
class Handler
private:

public:
Handler()
void(*irq)() = &irqHandler<PIN_1, PIN_2>;
attach_interrupt(0, irq);
attach_interrupt(0, &handler_2);


// static member function can have its address taken, also works as ISR
static void handler_2()
std::cout << "PIN_1: " << PIN_1 << "n";
std::cout << "PIN_2: " << PIN_2 << "n";

;

Handler<1, 2> a;
Handler<2, 3> b;

int main()

return 0;










share|improve this question
























  • You won't get around std::bind().

    – Swordfish
    Nov 15 '18 at 0:43






  • 1





    The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

    – user10605163
    Nov 15 '18 at 0:49














0












0








0








I have an object which needs to interface with an existing C api to register an in interrupt (void function taking no arguments). I can attach the interrupt to the function function(). However, I want to be able to pass in arguments to the function, but that would change the function signature. I thought a way around that would be to create an object to store the parameters (and modify them as necessary), and then pass in a method (or similar). However, I haven't been able to figure out how to do that.



I've tried passing in a lambda as [=]() std::cout << "a: " << a << "n"; , but it turns out lambdas with a capture can't be converted to function pointers. I've also tried a templated method (since it would get instantiated at compile time), but couldn't get it to work. I've seen some posts on SO talking about std::bind and std::function, but they often warn about virtual function overhead, which I'd like to avoid on an embedded platform for an ISR.



What is the best way to convert a paramterized function to a void(*)()?



#include <iostream>

void function()
std::cout << "Hello World!n";


void attach_interrupt(void(*fn)())
fn();


class A
int a;

public:
A(int a) : a(a)
attach_interrupt(function); // This works as expected
// attach_interrupt(method); // How do I make this work?
// attach_interrupt(method2<a>);


void method()
// something requiring a and b
std::cout << "a: " << a << "n";


template<int a>
void method2()
std::cout << "a: " << a << "n";

;

int main()

const int PIN_1 = 0;
const int PIN_2 = 1;
const int PIN_3 = 2;

A foo(PIN_1);
A bar(PIN_2);
A baz(PIN_3);

return 0;



EDIT: My solution, inspired by the selected answer:



#include <iostream>

void attach_interrupt(int pin, void(*fn)())
fn();


// Free function, which works as an ISR
template <unsigned int IRQ, unsigned int IRQ2>
static void irqHandler()

std::cout << "IRQ: " << IRQ << "n";
std::cout << "IRQ2: " << IRQ2 << "n";
;

template <unsigned int PIN_1, unsigned int PIN_2>
class Handler
private:

public:
Handler()
void(*irq)() = &irqHandler<PIN_1, PIN_2>;
attach_interrupt(0, irq);
attach_interrupt(0, &handler_2);


// static member function can have its address taken, also works as ISR
static void handler_2()
std::cout << "PIN_1: " << PIN_1 << "n";
std::cout << "PIN_2: " << PIN_2 << "n";

;

Handler<1, 2> a;
Handler<2, 3> b;

int main()

return 0;










share|improve this question
















I have an object which needs to interface with an existing C api to register an in interrupt (void function taking no arguments). I can attach the interrupt to the function function(). However, I want to be able to pass in arguments to the function, but that would change the function signature. I thought a way around that would be to create an object to store the parameters (and modify them as necessary), and then pass in a method (or similar). However, I haven't been able to figure out how to do that.



I've tried passing in a lambda as [=]() std::cout << "a: " << a << "n"; , but it turns out lambdas with a capture can't be converted to function pointers. I've also tried a templated method (since it would get instantiated at compile time), but couldn't get it to work. I've seen some posts on SO talking about std::bind and std::function, but they often warn about virtual function overhead, which I'd like to avoid on an embedded platform for an ISR.



What is the best way to convert a paramterized function to a void(*)()?



#include <iostream>

void function()
std::cout << "Hello World!n";


void attach_interrupt(void(*fn)())
fn();


class A
int a;

public:
A(int a) : a(a)
attach_interrupt(function); // This works as expected
// attach_interrupt(method); // How do I make this work?
// attach_interrupt(method2<a>);


void method()
// something requiring a and b
std::cout << "a: " << a << "n";


template<int a>
void method2()
std::cout << "a: " << a << "n";

;

int main()

const int PIN_1 = 0;
const int PIN_2 = 1;
const int PIN_3 = 2;

A foo(PIN_1);
A bar(PIN_2);
A baz(PIN_3);

return 0;



EDIT: My solution, inspired by the selected answer:



#include <iostream>

void attach_interrupt(int pin, void(*fn)())
fn();


// Free function, which works as an ISR
template <unsigned int IRQ, unsigned int IRQ2>
static void irqHandler()

std::cout << "IRQ: " << IRQ << "n";
std::cout << "IRQ2: " << IRQ2 << "n";
;

template <unsigned int PIN_1, unsigned int PIN_2>
class Handler
private:

public:
Handler()
void(*irq)() = &irqHandler<PIN_1, PIN_2>;
attach_interrupt(0, irq);
attach_interrupt(0, &handler_2);


// static member function can have its address taken, also works as ISR
static void handler_2()
std::cout << "PIN_1: " << PIN_1 << "n";
std::cout << "PIN_2: " << PIN_2 << "n";

;

Handler<1, 2> a;
Handler<2, 3> b;

int main()

return 0;







c++ c++11






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 16:17







Vasu

















asked Nov 15 '18 at 0:25









VasuVasu

44911129




44911129












  • You won't get around std::bind().

    – Swordfish
    Nov 15 '18 at 0:43






  • 1





    The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

    – user10605163
    Nov 15 '18 at 0:49


















  • You won't get around std::bind().

    – Swordfish
    Nov 15 '18 at 0:43






  • 1





    The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

    – user10605163
    Nov 15 '18 at 0:49

















You won't get around std::bind().

– Swordfish
Nov 15 '18 at 0:43





You won't get around std::bind().

– Swordfish
Nov 15 '18 at 0:43




1




1





The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

– user10605163
Nov 15 '18 at 0:49






The templated method would work as static, but then really it is the same as a templated free function. Would that be sufficient? The a in the templated method isn't the class member a anyway.

– user10605163
Nov 15 '18 at 0:49













2 Answers
2






active

oldest

votes


















2














So you want to register one and the same interrupt handler for different interrupts, each having equal, but individual data...



What about a free-standing template function with static data?



template <unsigned int IRQ>
void irqHandler()

static A a(IRQ);
a.doSomething();
;

void(*interruptVectorTable[12])() =

// ...
&irqHandler<7>,
// ...
&irqHandler<10>,
;





share|improve this answer























  • Thanks! This solution works well. I modified my question with my solution that's inspired by this.

    – Vasu
    Nov 15 '18 at 16:16


















0














Well here is a convoluted way to do this. It requires some boilerplate code so I wrapped that up in a couple of MACROS (yuck). For C++11 the locking is somewhat limited (read less efficient) but that can be improved upon if you have access to C++14 or above:



// ## Header Library Code

namespace static_dispatch

inline std::mutex& mutex()
static std::mutex mtx; return mtx;

inline std::lock_guard<std::mutex> lock_for_reading()
return std::lock_guard<std::mutex>(mutex());

inline std::lock_guard<std::mutex> lock_for_updates()
return std::lock_guard<std::mutex>(mutex());

inline std::vector<void*>& cbdb()

static std::vector<void*> vps;
return vps;


inline void register_cb(void(*cb)(), void* user_data)

auto lock = lock_for_updates();
cbdb().push_back(user_data);
cb(); // assign id under lock


inline void* retreive_cb(std::size_t id)

auto lock = lock_for_reading();
return cbdb()[id];


// namespace static_dispatch

#define CALLBACK_BOILERPLATE(id)
static auto id = std::size_t(-1);
if(id == std::size_t(-1)) id = static_dispatch::cbdb().size() - 1; return;

#define CALLBACK_RETREIVE_DATA(id, T)
reinterpret_cast<T*>(static_dispatch::retreive_cb(id))

// ## Application Code

class A

public:
void member_callback_1() const

std::cout << s << 'n';


private:
std::string s = "hello";
;

void callback_1()

CALLBACK_BOILERPLATE(id);

auto a = CALLBACK_RETREIVE_DATA(id, A);

a->member_callback_1();


// The framework that you need to register your
// callbacks with
void framework_register(void(*cb)()) cb();

int main()

A a;

// register callback with data structure
static_dispatch::register_cb(&callback_1, &a);

// Now register callback with framework because subsequent calls
// will invoke the real callback.
framework_register(&callback_1);

// etc...



As noted about if you have C++14 you can replace the mutex and locking code with the more efficient functions here:



inline std::shared_timed_mutex& mutex()
static std::shared_timed_mutex mtx; return mtx;

inline std::shared_lock<std::shared_timed_mutex> lock_for_reading()
return std::shared_lock<std::shared_timed_mutex>(mutex());

inline std::unique_lock<std::shared_timed_mutex> lock_for_updates()
return std::unique_lock<std::shared_timed_mutex>(mutex());





share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53310769%2fpass-class-method-as-void-function-pointer-c11%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    So you want to register one and the same interrupt handler for different interrupts, each having equal, but individual data...



    What about a free-standing template function with static data?



    template <unsigned int IRQ>
    void irqHandler()

    static A a(IRQ);
    a.doSomething();
    ;

    void(*interruptVectorTable[12])() =

    // ...
    &irqHandler<7>,
    // ...
    &irqHandler<10>,
    ;





    share|improve this answer























    • Thanks! This solution works well. I modified my question with my solution that's inspired by this.

      – Vasu
      Nov 15 '18 at 16:16















    2














    So you want to register one and the same interrupt handler for different interrupts, each having equal, but individual data...



    What about a free-standing template function with static data?



    template <unsigned int IRQ>
    void irqHandler()

    static A a(IRQ);
    a.doSomething();
    ;

    void(*interruptVectorTable[12])() =

    // ...
    &irqHandler<7>,
    // ...
    &irqHandler<10>,
    ;





    share|improve this answer























    • Thanks! This solution works well. I modified my question with my solution that's inspired by this.

      – Vasu
      Nov 15 '18 at 16:16













    2












    2








    2







    So you want to register one and the same interrupt handler for different interrupts, each having equal, but individual data...



    What about a free-standing template function with static data?



    template <unsigned int IRQ>
    void irqHandler()

    static A a(IRQ);
    a.doSomething();
    ;

    void(*interruptVectorTable[12])() =

    // ...
    &irqHandler<7>,
    // ...
    &irqHandler<10>,
    ;





    share|improve this answer













    So you want to register one and the same interrupt handler for different interrupts, each having equal, but individual data...



    What about a free-standing template function with static data?



    template <unsigned int IRQ>
    void irqHandler()

    static A a(IRQ);
    a.doSomething();
    ;

    void(*interruptVectorTable[12])() =

    // ...
    &irqHandler<7>,
    // ...
    &irqHandler<10>,
    ;






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 15 '18 at 2:03









    AconcaguaAconcagua

    12.7k32143




    12.7k32143












    • Thanks! This solution works well. I modified my question with my solution that's inspired by this.

      – Vasu
      Nov 15 '18 at 16:16

















    • Thanks! This solution works well. I modified my question with my solution that's inspired by this.

      – Vasu
      Nov 15 '18 at 16:16
















    Thanks! This solution works well. I modified my question with my solution that's inspired by this.

    – Vasu
    Nov 15 '18 at 16:16





    Thanks! This solution works well. I modified my question with my solution that's inspired by this.

    – Vasu
    Nov 15 '18 at 16:16













    0














    Well here is a convoluted way to do this. It requires some boilerplate code so I wrapped that up in a couple of MACROS (yuck). For C++11 the locking is somewhat limited (read less efficient) but that can be improved upon if you have access to C++14 or above:



    // ## Header Library Code

    namespace static_dispatch

    inline std::mutex& mutex()
    static std::mutex mtx; return mtx;

    inline std::lock_guard<std::mutex> lock_for_reading()
    return std::lock_guard<std::mutex>(mutex());

    inline std::lock_guard<std::mutex> lock_for_updates()
    return std::lock_guard<std::mutex>(mutex());

    inline std::vector<void*>& cbdb()

    static std::vector<void*> vps;
    return vps;


    inline void register_cb(void(*cb)(), void* user_data)

    auto lock = lock_for_updates();
    cbdb().push_back(user_data);
    cb(); // assign id under lock


    inline void* retreive_cb(std::size_t id)

    auto lock = lock_for_reading();
    return cbdb()[id];


    // namespace static_dispatch

    #define CALLBACK_BOILERPLATE(id)
    static auto id = std::size_t(-1);
    if(id == std::size_t(-1)) id = static_dispatch::cbdb().size() - 1; return;

    #define CALLBACK_RETREIVE_DATA(id, T)
    reinterpret_cast<T*>(static_dispatch::retreive_cb(id))

    // ## Application Code

    class A

    public:
    void member_callback_1() const

    std::cout << s << 'n';


    private:
    std::string s = "hello";
    ;

    void callback_1()

    CALLBACK_BOILERPLATE(id);

    auto a = CALLBACK_RETREIVE_DATA(id, A);

    a->member_callback_1();


    // The framework that you need to register your
    // callbacks with
    void framework_register(void(*cb)()) cb();

    int main()

    A a;

    // register callback with data structure
    static_dispatch::register_cb(&callback_1, &a);

    // Now register callback with framework because subsequent calls
    // will invoke the real callback.
    framework_register(&callback_1);

    // etc...



    As noted about if you have C++14 you can replace the mutex and locking code with the more efficient functions here:



    inline std::shared_timed_mutex& mutex()
    static std::shared_timed_mutex mtx; return mtx;

    inline std::shared_lock<std::shared_timed_mutex> lock_for_reading()
    return std::shared_lock<std::shared_timed_mutex>(mutex());

    inline std::unique_lock<std::shared_timed_mutex> lock_for_updates()
    return std::unique_lock<std::shared_timed_mutex>(mutex());





    share|improve this answer



























      0














      Well here is a convoluted way to do this. It requires some boilerplate code so I wrapped that up in a couple of MACROS (yuck). For C++11 the locking is somewhat limited (read less efficient) but that can be improved upon if you have access to C++14 or above:



      // ## Header Library Code

      namespace static_dispatch

      inline std::mutex& mutex()
      static std::mutex mtx; return mtx;

      inline std::lock_guard<std::mutex> lock_for_reading()
      return std::lock_guard<std::mutex>(mutex());

      inline std::lock_guard<std::mutex> lock_for_updates()
      return std::lock_guard<std::mutex>(mutex());

      inline std::vector<void*>& cbdb()

      static std::vector<void*> vps;
      return vps;


      inline void register_cb(void(*cb)(), void* user_data)

      auto lock = lock_for_updates();
      cbdb().push_back(user_data);
      cb(); // assign id under lock


      inline void* retreive_cb(std::size_t id)

      auto lock = lock_for_reading();
      return cbdb()[id];


      // namespace static_dispatch

      #define CALLBACK_BOILERPLATE(id)
      static auto id = std::size_t(-1);
      if(id == std::size_t(-1)) id = static_dispatch::cbdb().size() - 1; return;

      #define CALLBACK_RETREIVE_DATA(id, T)
      reinterpret_cast<T*>(static_dispatch::retreive_cb(id))

      // ## Application Code

      class A

      public:
      void member_callback_1() const

      std::cout << s << 'n';


      private:
      std::string s = "hello";
      ;

      void callback_1()

      CALLBACK_BOILERPLATE(id);

      auto a = CALLBACK_RETREIVE_DATA(id, A);

      a->member_callback_1();


      // The framework that you need to register your
      // callbacks with
      void framework_register(void(*cb)()) cb();

      int main()

      A a;

      // register callback with data structure
      static_dispatch::register_cb(&callback_1, &a);

      // Now register callback with framework because subsequent calls
      // will invoke the real callback.
      framework_register(&callback_1);

      // etc...



      As noted about if you have C++14 you can replace the mutex and locking code with the more efficient functions here:



      inline std::shared_timed_mutex& mutex()
      static std::shared_timed_mutex mtx; return mtx;

      inline std::shared_lock<std::shared_timed_mutex> lock_for_reading()
      return std::shared_lock<std::shared_timed_mutex>(mutex());

      inline std::unique_lock<std::shared_timed_mutex> lock_for_updates()
      return std::unique_lock<std::shared_timed_mutex>(mutex());





      share|improve this answer

























        0












        0








        0







        Well here is a convoluted way to do this. It requires some boilerplate code so I wrapped that up in a couple of MACROS (yuck). For C++11 the locking is somewhat limited (read less efficient) but that can be improved upon if you have access to C++14 or above:



        // ## Header Library Code

        namespace static_dispatch

        inline std::mutex& mutex()
        static std::mutex mtx; return mtx;

        inline std::lock_guard<std::mutex> lock_for_reading()
        return std::lock_guard<std::mutex>(mutex());

        inline std::lock_guard<std::mutex> lock_for_updates()
        return std::lock_guard<std::mutex>(mutex());

        inline std::vector<void*>& cbdb()

        static std::vector<void*> vps;
        return vps;


        inline void register_cb(void(*cb)(), void* user_data)

        auto lock = lock_for_updates();
        cbdb().push_back(user_data);
        cb(); // assign id under lock


        inline void* retreive_cb(std::size_t id)

        auto lock = lock_for_reading();
        return cbdb()[id];


        // namespace static_dispatch

        #define CALLBACK_BOILERPLATE(id)
        static auto id = std::size_t(-1);
        if(id == std::size_t(-1)) id = static_dispatch::cbdb().size() - 1; return;

        #define CALLBACK_RETREIVE_DATA(id, T)
        reinterpret_cast<T*>(static_dispatch::retreive_cb(id))

        // ## Application Code

        class A

        public:
        void member_callback_1() const

        std::cout << s << 'n';


        private:
        std::string s = "hello";
        ;

        void callback_1()

        CALLBACK_BOILERPLATE(id);

        auto a = CALLBACK_RETREIVE_DATA(id, A);

        a->member_callback_1();


        // The framework that you need to register your
        // callbacks with
        void framework_register(void(*cb)()) cb();

        int main()

        A a;

        // register callback with data structure
        static_dispatch::register_cb(&callback_1, &a);

        // Now register callback with framework because subsequent calls
        // will invoke the real callback.
        framework_register(&callback_1);

        // etc...



        As noted about if you have C++14 you can replace the mutex and locking code with the more efficient functions here:



        inline std::shared_timed_mutex& mutex()
        static std::shared_timed_mutex mtx; return mtx;

        inline std::shared_lock<std::shared_timed_mutex> lock_for_reading()
        return std::shared_lock<std::shared_timed_mutex>(mutex());

        inline std::unique_lock<std::shared_timed_mutex> lock_for_updates()
        return std::unique_lock<std::shared_timed_mutex>(mutex());





        share|improve this answer













        Well here is a convoluted way to do this. It requires some boilerplate code so I wrapped that up in a couple of MACROS (yuck). For C++11 the locking is somewhat limited (read less efficient) but that can be improved upon if you have access to C++14 or above:



        // ## Header Library Code

        namespace static_dispatch

        inline std::mutex& mutex()
        static std::mutex mtx; return mtx;

        inline std::lock_guard<std::mutex> lock_for_reading()
        return std::lock_guard<std::mutex>(mutex());

        inline std::lock_guard<std::mutex> lock_for_updates()
        return std::lock_guard<std::mutex>(mutex());

        inline std::vector<void*>& cbdb()

        static std::vector<void*> vps;
        return vps;


        inline void register_cb(void(*cb)(), void* user_data)

        auto lock = lock_for_updates();
        cbdb().push_back(user_data);
        cb(); // assign id under lock


        inline void* retreive_cb(std::size_t id)

        auto lock = lock_for_reading();
        return cbdb()[id];


        // namespace static_dispatch

        #define CALLBACK_BOILERPLATE(id)
        static auto id = std::size_t(-1);
        if(id == std::size_t(-1)) id = static_dispatch::cbdb().size() - 1; return;

        #define CALLBACK_RETREIVE_DATA(id, T)
        reinterpret_cast<T*>(static_dispatch::retreive_cb(id))

        // ## Application Code

        class A

        public:
        void member_callback_1() const

        std::cout << s << 'n';


        private:
        std::string s = "hello";
        ;

        void callback_1()

        CALLBACK_BOILERPLATE(id);

        auto a = CALLBACK_RETREIVE_DATA(id, A);

        a->member_callback_1();


        // The framework that you need to register your
        // callbacks with
        void framework_register(void(*cb)()) cb();

        int main()

        A a;

        // register callback with data structure
        static_dispatch::register_cb(&callback_1, &a);

        // Now register callback with framework because subsequent calls
        // will invoke the real callback.
        framework_register(&callback_1);

        // etc...



        As noted about if you have C++14 you can replace the mutex and locking code with the more efficient functions here:



        inline std::shared_timed_mutex& mutex()
        static std::shared_timed_mutex mtx; return mtx;

        inline std::shared_lock<std::shared_timed_mutex> lock_for_reading()
        return std::shared_lock<std::shared_timed_mutex>(mutex());

        inline std::unique_lock<std::shared_timed_mutex> lock_for_updates()
        return std::unique_lock<std::shared_timed_mutex>(mutex());






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 '18 at 2:09









        GalikGalik

        34.6k35280




        34.6k35280



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53310769%2fpass-class-method-as-void-function-pointer-c11%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            How to read a connectionString WITH PROVIDER in .NET Core?

            Node.js Script on GitHub Pages or Amazon S3

            Museum of Modern and Contemporary Art of Trento and Rovereto