我尝试在构造函数初始化列表中的lambda中捕获可变参数。这是一个说明问题的简单示例。
#include <functional>
#include <iostream>
void foo(int a)
{
std::cout << a << std::endl;
}
template<typename ...Args>
class Widget
{
public:
Widget(std::function<void(Args...)> f, Args... args)
: _f([=]() { f(args...); }) // compiler error here
{
}
void print() const { _f(); }
private:
std::function<void()> _f;
};
int main(int argc, char* argv[])
{
Widget<int> w(foo, 7);
w.print();
return 0;
}
在VS2013中,我收到以下编译错误:
error C3546: '...' : there are no parameter packs available to expand
error C2065: 'args' : undeclared identifier
以下版本的Widget
构造函数编译和工作。
Widget(std::function<void(Args...)> f, Args... args)
{
_f = [=]() { f(args...); };
}
Widget(std::function<void(Args...)> f, Args... args)
: _f(std::bind(f, args...))
{
}
更新: MS Visual C ++编译器团队修复了此问题,并将其包含在即将发布的Visual C ++版本中(see)。
答案 0 :(得分:1)
Lambda捕获可能是编译器最终实现的C ++ 11的最后一部分,如果某个特定编译器尚未实现它,或者它的实现是错误的,那就不足为奇了。据说,gcc直到最近才得到这个权利。
典型的方法是使用元组解决这个问题。使用std::make_tuple
将所有可变参数放入元组中,然后捕获元组。
然后,将元组转换回参数包。搜索stackoverflow,有几个例子说明如何做到这一点。
这会产生一大堆行李代码。但它是什么,它是什么,当编译器最终做对了,这个解决方法可以被删除,同时你会有一些有用的东西。或多或少。