我发现使用下面链接的答案中的代码效果很好,但在我的用例中存在问题。它有效地为非静态成员函数创建了一个“静态包装器”,以作为回调传递。
#include <stdio.h>
#include <functional>
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) {
return func(args...);
}
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
所以我在头文件中包含了这一点,然后各种类都有如下代码。问题是,当尝试在同一范围内定义两个这样的回调时,第二个会覆盖第一个。
typedef int (*callback_t)(int*,int*);
Callback<int(int*,int*)>::func = std::bind(&myClass::myMethod1, this, std::placeholders::_1, std::placeholders::_2);
callback_t func1 = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
register_task1_with_library(func1);
Callback<int(int*,int*)>::func = std::bind(&myClass::myMethod2, this, std::placeholders::_1, std::placeholders::_2);
callback_t func2 = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
register_task2_with_library(func2);
第一个注册的回调被重定向到第二个。 为此创建第二个“静态包装器”的最小更改是什么?似乎必须复制头文件的全部内容,用 Callback2 之类的内容替换 Callback,才能有第二个“静态包装器”可用.
还有一个更简单的示例可以显示相同的问题:
#include <iostream>
#include "callback.hpp"
void print1(std::string msg)
{
std::cout << "print1:\t" << msg << std::endl;
}
void print2(std::string msg)
{
std::cout << "print2:\t\t" << msg << std::endl;
}
int main(int argc, char ** argv)
{
typedef void (*callback_t)(std::string);
Callback<void(std::string)>::func = std::bind(print1, std::placeholders::_1);
callback_t func1 = static_cast<callback_t>(Callback<void(std::string)>::callback);
Callback<void(std::string)>::func = std::bind(print2, std::placeholders::_1);
callback_t func2 = static_cast<callback_t>(Callback<void(std::string)>::callback);
func1("howdy");
func2("partner");
return 0;
}
相关项目:https://stackoverflow.com/a/29817048/2725742和 使用c++类成员函数作为c回调函数,线程安全版本
修改后的模板如下是我在评论讨论后最终得到的,我的测试表明它在我的用例中很好。添加的“标签”参数有助于保持每个项目的唯一性。
template <typename T, int tag = 0>
struct Callback;
template <typename Ret, typename... Params, int tag>
struct Callback<Ret(Params...), tag> {
template <typename... Args>
static Ret callback(Args... args) {
return func(args...);
}
int m_tag = tag;
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params, int tag>
std::function<Ret(Params...)> Callback<Ret(Params...), tag>::func;
使用更新的静态包装模板(包括唯一标签),一些有关如何使用它的示例:
对于像
int myClass::mult(int a, int b)
这样的回调成员函数:
const int uniqueTag = 1234;
typedef int(*intCallback_t)(int, int);
Callback<int(int, int), uniqueTag>::func = std::bind(&myClass::mult, this, std::placeholders::_1, std::placeholders::_2);
intCallback_t intFunc = static_cast<intCallback_t>(Callback<int(int, int), uniqueTag>::callback);
或者对于像
void myClass::callback()
这样的回调成员函数:
const int uniqueTag = 4321;
typedef void(*callback_t)();
Callback<void(), uniqueTag>::func = std::bind(&myClass::callback, this);
callback_tintFunc = static_cast<callback_t>(Callback<void(), uniqueTag>::callback);