存储可变参数和回调以供以后使用
Storing variadic parameter and callback for later usage
我想创建一个带有可变参数的简单但通用的回调。我还需要存储它们,因为稍后会调用回调(从使用存储的不同线程)。
这是我到目前为止所拥有的:
#include <iostream>
#include <string>
using namespace std;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
FROM SOMESTORAGE get the callback and params
Do the reading
string result = "CONTENT";
Call the callback with result string and params
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(string filename, ReadFileCallback callback, T ...params) {
cout << "fileMgr_ReadWithCallback is processing file: " << filename << endl;
// string content = "CONTENT";
// callback(content, params...);
SOMESTORAGE = callback + params;
}
void readFileResult(string contents, int id) {
cout << "readFileResult callback: contents=" << contents << ", id=" << id << endl;
}
void readFile(string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
return 0;
}
但我不想在fileMgr_ReadWithCallback
中调用回调,因为它应该是一个异步方法,所以我宁愿存储回调函数及其参数,稍后在文件管理器中使用它能够执行操作。
所以问题是,将 ReadFileCallback
和 ...T
存储到结构中的方法是什么?
或者如果有更好的方法,请告诉我。
我需要可变参数,因为有时额外的参数只是一个整数,但有时它可以是 2 个整数或 1 个字符串等,我想保持 FileManager 通用。
我仅限于 C++11,但可以使用 Boost。
您可以通过 auto storedParams = std::make_tuple(params...)
将参数存储在元组中。稍后您可以简单地使用 std::apply(callback, storedParams )
.
调用您的回调函数
要添加附加参数(如内容),您可以使用 std::tuple_cat(std::make_tuple(content), storedParams )
。
我会分别存储参数和回调。
顺便说一句:std::apply 仅适用于 C++17 - 有什么可以模拟的吗(也许在 boost 中)?否则我会尝试使用 cppreference 上显示的 std::invoke 和 std::apply 的实现(只需删除 constexpr...)。
在这里你可以找到代码:https://godbolt.org/z/z9MP3M
但是你需要添加std::apply(这是最难的部分)。为什么你需要使用这么老的编译器?
更新
也许您可以使用 std::function 的类型擦除功能,请参阅 here:
#include <iostream>
#include <string>
#include <functional>
static std::function<void(std::string)> fileManagerStorage;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
//FROM SOMESTORAGE get the callback and params
//Do the reading
std::string content = "CONTENT";
fileManagerStorage(content);
//Call the callback with result string and params
fileManagerStorage(content);
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(std::string filename, ReadFileCallback callback, T ...params) {
std::cout << "fileMgr_ReadWithCallback is processing file: " << filename << std::endl;
// string content = "CONTENT";
// callback(content, params...);
fileManagerStorage = [=](std::string content){
callback(content, params...);
};
}
void readFileResult(std::string contents, int id) {
std::cout << "readFileResult callback: contents=" << contents << ", id=" << id << std::endl;
}
void readFile(std::string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
return 0;
}
(您不应将存储存储为全局变量 - 将其存储在您的线程中...)
首先,依赖全局变量并不是一个好主意,因为如果在之前的读取仍在进行时调用 readFile
会给出错误的结果。所以你真的应该将整个阅读过程封装在 class.
中
您需要使用 lambda 或 std::bind
,因为 callback
的参数在 fileMgr_ReadWithCallback
函数之外是未知的。
因此您创建了一个包装回调,接受 std::string
作为参数。并使用 lambda 捕获参数,lambda 接受一个字符串作为参数,并将字符串和 params
传递给回调:
storage = [=](std::string s) {
callback(s, params...);
};
这就是代码的样子(但正如我已经说过的那样,这是糟糕的设计)
#include <functional>
#include <iostream>
std::function<void(std::string)> storage;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
std::string result = "CONTENT";
storage(result);
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(std::string filename, ReadFileCallback callback, T ...params) {
std::cout << "fileMgr_ReadWithCallback is processing file: " << filename << std::endl;
storage = [=](std::string s) {
callback(s, params...);
};
}
void readFileResult(std::string contents, int id) {
std::cout << "readFileResult callback: contents=" << contents << ", id=" << id << std::endl;
}
void readFile(std::string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
fileMgr_DoneWithOtherstuff_DoTheReads();
return 0;
}
我想创建一个带有可变参数的简单但通用的回调。我还需要存储它们,因为稍后会调用回调(从使用存储的不同线程)。
这是我到目前为止所拥有的:
#include <iostream>
#include <string>
using namespace std;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
FROM SOMESTORAGE get the callback and params
Do the reading
string result = "CONTENT";
Call the callback with result string and params
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(string filename, ReadFileCallback callback, T ...params) {
cout << "fileMgr_ReadWithCallback is processing file: " << filename << endl;
// string content = "CONTENT";
// callback(content, params...);
SOMESTORAGE = callback + params;
}
void readFileResult(string contents, int id) {
cout << "readFileResult callback: contents=" << contents << ", id=" << id << endl;
}
void readFile(string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
return 0;
}
但我不想在fileMgr_ReadWithCallback
中调用回调,因为它应该是一个异步方法,所以我宁愿存储回调函数及其参数,稍后在文件管理器中使用它能够执行操作。
所以问题是,将 ReadFileCallback
和 ...T
存储到结构中的方法是什么?
或者如果有更好的方法,请告诉我。
我需要可变参数,因为有时额外的参数只是一个整数,但有时它可以是 2 个整数或 1 个字符串等,我想保持 FileManager 通用。
我仅限于 C++11,但可以使用 Boost。
您可以通过 auto storedParams = std::make_tuple(params...)
将参数存储在元组中。稍后您可以简单地使用 std::apply(callback, storedParams )
.
要添加附加参数(如内容),您可以使用 std::tuple_cat(std::make_tuple(content), storedParams )
。
我会分别存储参数和回调。
顺便说一句:std::apply 仅适用于 C++17 - 有什么可以模拟的吗(也许在 boost 中)?否则我会尝试使用 cppreference 上显示的 std::invoke 和 std::apply 的实现(只需删除 constexpr...)。
在这里你可以找到代码:https://godbolt.org/z/z9MP3M
但是你需要添加std::apply(这是最难的部分)。为什么你需要使用这么老的编译器?
更新
也许您可以使用 std::function 的类型擦除功能,请参阅 here:
#include <iostream>
#include <string>
#include <functional>
static std::function<void(std::string)> fileManagerStorage;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
//FROM SOMESTORAGE get the callback and params
//Do the reading
std::string content = "CONTENT";
fileManagerStorage(content);
//Call the callback with result string and params
fileManagerStorage(content);
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(std::string filename, ReadFileCallback callback, T ...params) {
std::cout << "fileMgr_ReadWithCallback is processing file: " << filename << std::endl;
// string content = "CONTENT";
// callback(content, params...);
fileManagerStorage = [=](std::string content){
callback(content, params...);
};
}
void readFileResult(std::string contents, int id) {
std::cout << "readFileResult callback: contents=" << contents << ", id=" << id << std::endl;
}
void readFile(std::string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
return 0;
}
(您不应将存储存储为全局变量 - 将其存储在您的线程中...)
首先,依赖全局变量并不是一个好主意,因为如果在之前的读取仍在进行时调用 readFile
会给出错误的结果。所以你真的应该将整个阅读过程封装在 class.
您需要使用 lambda 或 std::bind
,因为 callback
的参数在 fileMgr_ReadWithCallback
函数之外是未知的。
因此您创建了一个包装回调,接受 std::string
作为参数。并使用 lambda 捕获参数,lambda 接受一个字符串作为参数,并将字符串和 params
传递给回调:
storage = [=](std::string s) {
callback(s, params...);
};
这就是代码的样子(但正如我已经说过的那样,这是糟糕的设计)
#include <functional>
#include <iostream>
std::function<void(std::string)> storage;
void fileMgr_DoneWithOtherstuff_DoTheReads() {
std::string result = "CONTENT";
storage(result);
}
template<class ReadFileCallback, class ...T>
void fileMgr_ReadWithCallback(std::string filename, ReadFileCallback callback, T ...params) {
std::cout << "fileMgr_ReadWithCallback is processing file: " << filename << std::endl;
storage = [=](std::string s) {
callback(s, params...);
};
}
void readFileResult(std::string contents, int id) {
std::cout << "readFileResult callback: contents=" << contents << ", id=" << id << std::endl;
}
void readFile(std::string filename, int id) {
fileMgr_ReadWithCallback(filename, readFileResult, id);
}
int main()
{
int fileId = 1;
readFile("myfile", fileId);
fileMgr_DoneWithOtherstuff_DoTheReads();
return 0;
}