Pass class method as void function pointer (C++11)
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
add a comment |
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
You won't get aroundstd::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? Thea
in the templated method isn't the class membera
anyway.
– user10605163
Nov 15 '18 at 0:49
add a comment |
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
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
c++ c++11
edited Nov 15 '18 at 16:17
Vasu
asked Nov 15 '18 at 0:25
VasuVasu
44911129
44911129
You won't get aroundstd::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? Thea
in the templated method isn't the class membera
anyway.
– user10605163
Nov 15 '18 at 0:49
add a comment |
You won't get aroundstd::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? Thea
in the templated method isn't the class membera
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
add a comment |
2 Answers
2
active
oldest
votes
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>,
;
Thanks! This solution works well. I modified my question with my solution that's inspired by this.
– Vasu
Nov 15 '18 at 16:16
add a comment |
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());
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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>,
;
Thanks! This solution works well. I modified my question with my solution that's inspired by this.
– Vasu
Nov 15 '18 at 16:16
add a comment |
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>,
;
Thanks! This solution works well. I modified my question with my solution that's inspired by this.
– Vasu
Nov 15 '18 at 16:16
add a comment |
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>,
;
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>,
;
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
add a comment |
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
add a comment |
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());
add a comment |
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());
add a comment |
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());
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());
answered Nov 15 '18 at 2:09
GalikGalik
34.6k35280
34.6k35280
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 membera
anyway.– user10605163
Nov 15 '18 at 0:49