从作为参数传递的函数中提取参数
Extracting a parameter from a function passed as parameter
我有以下功能:
void Class1::MainThreadFunction(const __int64 param) {
if(GetCurrentThreadId() != System::MainThreadID) {
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
void Class2::RunInMainThread(void(__closure* FuncToCall)(const __int64 ParToExtract),
const __int64 fP1) {
struct {
__int64 P1;
void(__closure* F)(const __int64);
void __fastcall FTC() { F(P1); }
} Args = {fP1, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
所以我想做的是提取 FuncToCall
中的第一个参数,上面名为 ParToExtract
用于初始化 Args
结构。换句话说,结构中的 P1
应该从名为 ParToExtract
.
的传递函数接收 const __int64
上面的方法有效,但我目前作为一种解决方法将参数作为 fP1
传递,我用它来初始化 P1
但肯定有更好的方法来做到这一点。
额外的好处是在 RunInMainThread
中有可变数量的函数参数(但我暂时要避免使用 C++11 <functional>
)。
请不要使用基于 lambda 的(或 C++11 功能)- 这是我暂时还不能使用的另一件事。
TThread::Synchronize()
调用的方法的签名必须匹配 TThreadMethod
类型:
void __fastcall (__closure *TThreadMethod)(void);
所以不能直接通过它传递参数。不要通过代理函数,而是使用 lambda:
void MainThreadFunction(int64_t param) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [¶m]{ MainThreadFunction(param); } );
//...
}
为了拥有可变数量的参数,您可以将其设为函数模板:
template< class... Args >
void MainThreadFunction(Args&&... args) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [&args...] {
MainThreadFunction(std::forward<Args>(args)...);
}
);
//...
}
使用 classic(C++11 之前)编译器时,您通常会使用 class 私有变量来携带信息。
您已经拥有的是在 C++Builder 的 "classic" (pre-C++11) 编译器中处理这种情况的正确(也是唯一)方法。
为了支持可变数量的参数,您将不得不使用多个重载,没有其他选择(无需深入研究 low-level 内联汇编来手动设置调用堆栈,但即便如此,它也可能无法跨线程边界正常工作),例如:
void Class1::MainThreadFunction()
{
if (GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction);
return;
}
//...
}
void Class1::MainThreadFunction(const __int64 param)
{
if(GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
// and so on as needed ...
template<typename FuncType>
void Class2::RunInMainThread(FuncType FuncToCall)
{
struct {
FuncType F;
void __fastcall FTC() { F(); }
} Args = {FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType param)
{
struct {
const ParamType &P;
FuncType F;
void __fastcall FTC() { F(P); }
} Args = {param, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType1, typename ParamType2>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType1 param1, const ParamType2 param2)
{
struct {
const ParamType1 &P1;
const ParamType2 &P2;
FuncType F;
void __fastcall FTC() { F(P1, P2); }
} Args = {param1, param2, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
// and so on as needed...
如果您查看各种 RTL 头文件,例如 sysvari.h
和 utilcls.h
,使用重载是 Borland 本身在其自己的几个 API 中解决参数数量可变问题的方式,有时超过 30 个参数,足以处理大多数用户代码。
我有以下功能:
void Class1::MainThreadFunction(const __int64 param) {
if(GetCurrentThreadId() != System::MainThreadID) {
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
void Class2::RunInMainThread(void(__closure* FuncToCall)(const __int64 ParToExtract),
const __int64 fP1) {
struct {
__int64 P1;
void(__closure* F)(const __int64);
void __fastcall FTC() { F(P1); }
} Args = {fP1, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
所以我想做的是提取 FuncToCall
中的第一个参数,上面名为 ParToExtract
用于初始化 Args
结构。换句话说,结构中的 P1
应该从名为 ParToExtract
.
const __int64
上面的方法有效,但我目前作为一种解决方法将参数作为 fP1
传递,我用它来初始化 P1
但肯定有更好的方法来做到这一点。
额外的好处是在 RunInMainThread
中有可变数量的函数参数(但我暂时要避免使用 C++11 <functional>
)。
请不要使用基于 lambda 的(或 C++11 功能)- 这是我暂时还不能使用的另一件事。
TThread::Synchronize()
调用的方法的签名必须匹配 TThreadMethod
类型:
void __fastcall (__closure *TThreadMethod)(void);
所以不能直接通过它传递参数。不要通过代理函数,而是使用 lambda:
void MainThreadFunction(int64_t param) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [¶m]{ MainThreadFunction(param); } );
//...
}
为了拥有可变数量的参数,您可以将其设为函数模板:
template< class... Args >
void MainThreadFunction(Args&&... args) {
if(GetCurrentThreadId() != System::MainThreadID)
TThread::Synchronize(nullptr, [&args...] {
MainThreadFunction(std::forward<Args>(args)...);
}
);
//...
}
使用 classic(C++11 之前)编译器时,您通常会使用 class 私有变量来携带信息。
您已经拥有的是在 C++Builder 的 "classic" (pre-C++11) 编译器中处理这种情况的正确(也是唯一)方法。
为了支持可变数量的参数,您将不得不使用多个重载,没有其他选择(无需深入研究 low-level 内联汇编来手动设置调用堆栈,但即便如此,它也可能无法跨线程边界正常工作),例如:
void Class1::MainThreadFunction()
{
if (GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction);
return;
}
//...
}
void Class1::MainThreadFunction(const __int64 param)
{
if(GetCurrentThreadId() != System::MainThreadID)
{
RunInMainThread(MainThreadFunction, param);
return;
}
//...
}
// and so on as needed ...
template<typename FuncType>
void Class2::RunInMainThread(FuncType FuncToCall)
{
struct {
FuncType F;
void __fastcall FTC() { F(); }
} Args = {FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType param)
{
struct {
const ParamType &P;
FuncType F;
void __fastcall FTC() { F(P); }
} Args = {param, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
template<typename FuncType, typename ParamType1, typename ParamType2>
void Class2::RunInMainThread(FuncType FuncToCall, const ParamType1 param1, const ParamType2 param2)
{
struct {
const ParamType1 &P1;
const ParamType2 &P2;
FuncType F;
void __fastcall FTC() { F(P1, P2); }
} Args = {param1, param2, FuncToCall};
TThread::Synchronize(NULL, &Args.FTC);
}
// and so on as needed...
如果您查看各种 RTL 头文件,例如 sysvari.h
和 utilcls.h
,使用重载是 Borland 本身在其自己的几个 API 中解决参数数量可变问题的方式,有时超过 30 个参数,足以处理大多数用户代码。