将具有默认参数的lambda函数复制到变量
Copying a lambda function with default parameters to a variable
考虑以下代码:
#include <iostream>
#include <functional>
using namespace std;
int main() {
auto f = [](int a = 3) {cout << a << endl; };
f(2); // OK
f(); // OK
auto g = f;
g(2); // OK
g(); // OK
function<void(int)> h = f;
h(2); // OK
h(); // Error! How to make this work?
return 0;
}
如何声明h
的行为与f
和g
相同?
std::function
有一个固定签名。这是一个设计选择,而不是硬性要求。编写一个支持多个签名的伪std::function
并不困难:
template<class...Sigs>
struct functions;
template<>
struct functions<> {
functions()=default;
functions(functions const&)=default;
functions(functions&&)=default;
functions& operator=(functions const&)=default;
functions& operator=(functions&&)=default;
private:
struct never_t {private:never_t(){};};
public:
void operator()(never_t)const =delete;
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, functions>{}, int>* =nullptr
>
functions(F&&) {}
};
template<class S0, class...Sigs>
struct functions<S0, Sigs...>:
std::function<S0>,
functions<Sigs...>
{
functions()=default;
functions(functions const&)=default;
functions(functions&&)=default;
functions& operator=(functions const&)=default;
functions& operator=(functions&&)=default;
using std::function<S0>::operator();
using functions<Sigs...>::operator();
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, functions>{}, int>* =nullptr
>
functions(F&& f):
std::function<S0>(f),
functions<Sigs...>(std::forward<F>(f))
{}
};
用途:
auto f = [](int a = 3) {std::cout << a << std::endl; };
functions<void(int), void()> fs = f;
fs();
fs(3);
活生生的例子。
这将为每个重载创建一个单独的lambda副本。通过仔细的铸造,甚至可以为不同的重载提供不同的Lambda。
您可以编写一个不这样做的程序,但它基本上需要用更高级的内部状态重新实现std::function
。
上面的更高级版本将避免使用线性继承,因为这会导致O(n^2)代码和O(n)递归模板对签名数量的深度。平衡的二进制树继承将其归结为生成的O(n-lgn)代码和O(lgn)深度。
工业强度版本会将传入的lambda存储一次,使用小对象优化,有一个使用二进制继承策略来调度函数调用的手动伪vtable,并将调度到函数指针存储在所述伪vtable中。它将在每个类(而不是每个实例)的基础上占用O(#签名)*sizeof(函数指针)空间,并且每个实例的开销大约与std::function
一样多。
但这对于一个SO职位来说有点过分了,不是吗?
启动
我喜欢@Yakk提出的不错的解决方案。
也就是说,您可以通过避免std::function
s并使用lambda、可变模板和std::forward
的代理函数来执行类似的操作,如下所示:
#include<functional>
#include<utility>
#include<iostream>
template<typename... Args>
void f(Args&&... args) {
auto g = [](int a = 3) { std::cout << a << std::endl; };
g(std::forward<Args>(args)...);
};
int main() {
f(2);
f();
}
把上面的想法放在函子中,你就会得到一个几乎相同的类似函数的对象。
它的问题是参数没有得到严格的验证
无论如何,如果误用,它将在编译时失败。
相关文章:
- 使用 memcpy 函数C++复制字符数组
- 使用复制构造函数复制双精度数组
- VB.NET DLL中的C++DLL函数复制
- 使用SSE内部函数复制少量数据时出现问题
- 不可变的 lambda 函数:复制捕获的变量是否允许是 const
- C 无可行的构造函数复制类型的变量
- 没有可行的构造函数复制类型 'MyString' 的数组元素
- 编译时,复制构造函数/复制分配和正常功能调用优化之间是否存在任何区别
- 将具有默认参数的lambda函数复制到变量
- 如何最小化调用列表构造函数(复制构造函数)的次数?
- C 11矢量构造函数复制与范围
- std::函数复制运算符 (MSVC2012) 的奇怪行为
- 从函数复制成本返回STL向量
- 我定义了一个非复制构造函数;复制构造函数还会被隐式定义吗
- 可以将构造函数复制为转换运算符
- 标准::函数复制参数
- C++:strcpy 函数复制空值
- 将基类指针的构造函数复制到子类
- Zlib解压缩函数复制而不是解压缩
- C++树类:构造函数/复制/内存泄漏