为何无法给Lambda函数参数加默认值?求替代实现方案
解决Lambda作为函数默认参数且带decay默认值的问题
问题背景
在实现EMA权重更新方法时,希望将Lambda作为函数的默认参数,同时给decay设置默认值(如0.999),但在MSVC下遇到error C2383: 'updwp': default-arguments are not allowed on this symbol报错——C++标准不允许在函数指针/引用类型的参数中声明默认参数,直接给Lambda参数加默认值、用std::bind结合std::function的尝试均失效。
可行解决方案
方案1:将decay设为独立默认参数
把decay提取为函数顶层参数并设置默认值,默认Lambda仅接收参数不声明默认值,调用时传递默认decay即可。这种方式既规避了函数指针的默认参数限制,又保留了decay的可配置性。
#include <torch/torch.h> void ema_update(int i, const NetImpl& mdl, double decay = 0.999, // 默认Lambda不声明decay的默认值,仅接收传入的参数 void (*updwp)(torch::Tensor&, const torch::Tensor&, double) = [](torch::Tensor& w, const torch::Tensor& w1, double decay) { w.set_data(w.data().detach() * decay + w1.detach() * (1. - decay)); }, void (*updw)(torch::Tensor&, const torch::Tensor&, double) = [](torch::Tensor& w, const torch::Tensor& w1, double decay) { w = w.detach() * decay; w += w1.detach() * (1. - decay); }) { // 权重更新逻辑示例:遍历模型参数调用更新函数 for (auto& [name, param] : mdl.named_parameters()) { torch::Tensor w_ema = /* 对应EMA权重张量 */; updwp(w_ema, param, decay); } }
简化测试示例:
void f(double b = 0.77, void (*pf)(int&, double) = [](int& a, double b) { a *= b; }) { int a = 9; pf(a, b); // 传递默认或自定义的b值 }
方案2:Lambda内部捕获/定义默认decay
如果decay的默认值无需外部修改,可以直接在默认Lambda内部固定decay值,此时函数指针的参数列表无需包含decay,彻底避免默认参数冲突。
#include <torch/torch.h> void ema_update(int i, const NetImpl& mdl, void (*updwp)(torch::Tensor&, const torch::Tensor&) = [](torch::Tensor& w, const torch::Tensor& w1) { const double decay = 0.999; // 内部固定默认值 w.set_data(w.data().detach() * decay + w1.detach() * (1. - decay)); }, void (*updw)(torch::Tensor&, const torch::Tensor&) = [](torch::Tensor& w, const torch::Tensor& w1) { const double decay = 0.999; w = w.detach() * decay; w += w1.detach() * (1. - decay); }) { // 权重更新逻辑示例 for (auto& [name, param] : mdl.named_parameters()) { torch::Tensor w_ema = /* 对应EMA权重张量 */; updwp(w_ema, param); // 无需传递decay } }
简化测试示例:
void f(void (*pf)(int&) = [](int& a) { const double b = 0.77; // 内部固定默认值 a *= b; }) { int a = 9; pf(a); }
修复std::function + std::bind的写法
之前的std::bind失败是因为参数顺序和占位符使用错误,调整后即可正常工作:
#include <functional> void f3(double b = 0.77, std::function<void(double, int&)> fa = [](double b, int& a) { a *= b; }) { int a = 9; // 用占位符标记后续传入的int&参数 auto f = std::bind(fa, b, std::placeholders::_1); f(a); }
失败原因说明
- C++标准禁止在函数指针/引用类型的参数中声明默认参数,因此
void (&updwp)(..., double decay = 0.999)属于非法语法,MSVC严格执行了这一规则。 - 最初的
std::bind尝试未使用占位符,导致参数绑定顺序错误,无法匹配Lambda的参数列表。
内容的提问来源于stack exchange,提问作者AnArrayOfFunctions
相关产品推荐
相关产品推荐

