传递函数模板的地址
Passing the address of a function template
考虑以下函数:
template <int node>
void RemainingEnergyTrace (double oldValue, double newValue)
{
std::stringstream ss;
ss << "Energy_" << node << ".log";
static std::fstream f (ss.str().c_str(), std::ios::out);
f << Simulator::Now().GetSeconds() << " Remaining energy=" << newValue << std::endl;
}
注意函数 int node 的模板定义。我尝试在 main() 中传递这个函数的地址:
int inc = 0;
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
生成以下错误:
error: the value of ‘inc’ is not usable in a constant expression
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
^
error: no matching function for call to ‘MakeCallback(<unresolved overloaded function type>)’
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
^
但是,以下语句有效:
eSources.Get (0)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<0>));
总而言之,一个实际的数字有效,但当以模板格式传递整数变量时,它不起作用。是因为整数变量必须是 const 类型(如错误提示的那样)吗?
我正在尝试 运行 一个循环并为不同的整数值传递函数的地址。我怎样才能使这项工作?
for(int inc = 0; inc<nWifi; inc++)
{
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
}
简而言之,you can't。由于模板在编译时扩展,因此您也需要在编译时提供值。如果 nWifi
是一个仅在运行时可用的值,则需要使用常规参数:
void RemainingEnergyTrace (double oldValue, double newValue, int node);
如果您想要创建 部分应用的 函数以传递给您的 MakeCallback
,您可以使用 lambdas 创建它们:
for(int inc = 0; inc<nWifi; inc++)
{
auto callback = [=](double oldVal, double newVal) {
RemainingEnergyTrace(oldVal, newVal, inc);
};
...
}
但是这个 won't decay to a function pointer,因此您可能需要将 MakeCallback
API 更改为例如使用 std::function
(这是现在的首选方法)或采用附加参数1,或者使用一些库来提供您需要的委托功能。
1通常,采用函数指针的 C 或 C++ API 也会采用额外的 void*
参数与函数指针一起存储。然后,在调用时,指针将传递给该函数,并存储必要的闭包数据(在您的情况下,它可能指向驻留在内存中某处的 inc
值)。不知道 MakeCallback
是如何工作的,就不可能说出什么是最好的解决方案。
考虑以下函数:
template <int node>
void RemainingEnergyTrace (double oldValue, double newValue)
{
std::stringstream ss;
ss << "Energy_" << node << ".log";
static std::fstream f (ss.str().c_str(), std::ios::out);
f << Simulator::Now().GetSeconds() << " Remaining energy=" << newValue << std::endl;
}
注意函数 int node 的模板定义。我尝试在 main() 中传递这个函数的地址:
int inc = 0;
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
生成以下错误:
error: the value of ‘inc’ is not usable in a constant expression
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
^
error: no matching function for call to ‘MakeCallback(<unresolved overloaded function type>)’
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
^
但是,以下语句有效:
eSources.Get (0)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<0>));
总而言之,一个实际的数字有效,但当以模板格式传递整数变量时,它不起作用。是因为整数变量必须是 const 类型(如错误提示的那样)吗?
我正在尝试 运行 一个循环并为不同的整数值传递函数的地址。我怎样才能使这项工作?
for(int inc = 0; inc<nWifi; inc++)
{
eSources.Get (inc)->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback(&RemainingEnergyTrace<inc>));
}
简而言之,you can't。由于模板在编译时扩展,因此您也需要在编译时提供值。如果 nWifi
是一个仅在运行时可用的值,则需要使用常规参数:
void RemainingEnergyTrace (double oldValue, double newValue, int node);
如果您想要创建 部分应用的 函数以传递给您的 MakeCallback
,您可以使用 lambdas 创建它们:
for(int inc = 0; inc<nWifi; inc++)
{
auto callback = [=](double oldVal, double newVal) {
RemainingEnergyTrace(oldVal, newVal, inc);
};
...
}
但是这个 won't decay to a function pointer,因此您可能需要将 MakeCallback
API 更改为例如使用 std::function
(这是现在的首选方法)或采用附加参数1,或者使用一些库来提供您需要的委托功能。
1通常,采用函数指针的 C 或 C++ API 也会采用额外的 void*
参数与函数指针一起存储。然后,在调用时,指针将传递给该函数,并存储必要的闭包数据(在您的情况下,它可能指向驻留在内存中某处的 inc
值)。不知道 MakeCallback
是如何工作的,就不可能说出什么是最好的解决方案。