我有一个对象,该对象需要与现有的C api进行接口才能注册in中断(void函数不带参数)。我可以将中断附加到函数function()
上。但是,我希望能够将参数传递给函数,但这将更改函数签名。我想一种解决方法是创建一个对象来存储参数(并根据需要修改它们),然后传入一个方法(或类似方法)。但是,我还无法弄清楚该怎么做。
我尝试将lambda作为[=](){ std::cout << "a: " << a << "\n"; }
传递,但事实证明带有捕获的lambda无法转换为函数指针。我也尝试了模板化方法(因为它会在编译时实例化),但无法使其正常工作。我曾经在SO上看到过一些关于std::bind
和std::function
的帖子,但是他们经常警告虚函数开销,我想避免在用于ISR的嵌入式平台上使用它们。
将参数化的函数转换为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;
}
编辑:我的解决方案受到所选答案的启发:
#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;
}
答案 0 :(得分:2)
因此,您想为一个不同的中断注册一个相同的中断处理程序,每个中断具有相等但独立的数据...
具有静态数据的独立模板功能如何?
template <unsigned int IRQ>
void irqHandler()
{
static A a(IRQ);
a.doSomething();
};
void(*interruptVectorTable[12])() =
{
// ...
&irqHandler<7>,
// ...
&irqHandler<10>,
};
答案 1 :(得分:0)
这是一种复杂的方法。它需要一些样板代码,所以我将其包装在几个MACROS(糟糕的)中。对于C++11
,锁定受到一定程度的限制(读取效率较低),但是如果您可以访问C++14
或更高版本,则可以进行改进:
// ## 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...
}
关于是否拥有C++14
的说明,您可以在此处用更有效的功能替换互斥体和锁定代码:
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()); }