查看std::function
的一些静态分配替换,这些替换不涉及任何std
库
很快就会意识到,有些仅支持无状态lambdas(有什么原因吗?(
例如,vl似乎可以很好地与[&]
配合使用,而etl则不然——我得到了垃圾值。
我的测试代码:
template<typename Func, typename... Args>
class Callback
{
public:
Func dFunc;
etl::delegate<void(Func v, int& ret )> dLambda;
vl::Func<void(Func func, int& ret)> dLambda1;
Callback(Func func, Args&...args) :
dFunc(func),
dLambda([&args...](Func v, int& ret) { ret = v(args...); }),
dLambda1([&args...](Func v, int& ret) { ret = v(args...); })
{}
void run(int& ret)
{
dLambda(dFunc, ret );
//auto test = dLambda;
//CHECK_EQUAL(true, is_stateless<decltype(test)>::value);
}
void run1(int & ret)
{
dLambda1(dFunc, ret);
//auto test1 = dLambda1;
//CHECK_EQUAL(true, is_stateless<decltype(test1)>::value);
}
};
我测试了他们两个的is_stateless
无状态测试,两个都说不是!(??(此外,测试本身"修复"了一个不工作的替代品(??(
我想知道在支持[&]
的基础上添加了什么?我应该找什么?
ETL文档中etl::delegate
根本不拥有lambda,请参阅https://www.etlcpp.com/delegate.html.它只存储一个指向传递对象的指针。它根本不存储lambda。另请参阅上的代码https://github.com/ETLCPP/etl/blob/master/include/etl/private/delegate_cpp11.h#L117.
与链接文档所暗示的相反,直接将lambda表达式作为参数传递给etl::delegate
的构造函数总是未定义的行为,无论它是否是无状态的。因为etl::delegate
存储了一个指向传递对象的指针,所以当调用operator()
时,它将尝试在过期对象上调用非静态成员函数。
如果lambda是无状态的,那么未定义的行为就不太可能导致编译程序的意外行为,因此在无效指针上调用的编译成员函数实际上不必访问/取消引用指针。
您必须将lambda存储在etl::delegate
之外的某个位置。
我不知道为什么作者没有为构造函数添加lambda到函数指针的转换,以用于不捕获lambda和/或不允许的右值参数。现在的书写方式极易被误用。
vl::Func
似乎实现了一个类似于std::function
的模式,并且确实拥有传递的可调用性。这也意味着它使用new
将可调用的存储在动态内存中,但据我所知,没有匹配的delete
。
因此,它不是静态分配替换。它确实使用了动态分配。
(很抱歉我之前断言它泄露了对象。我完全误读了代码。就我对代码的肤浅观察而言,我再也看不到实现中有任何缺陷了。(
如果没有动态分配,就不可能实现std::function
的一般功能。同时拥有可调用对象的std::function
的静态分配替换必须具有一些参数,以限制其可以存储的可调用对象或类似对象的最大大小,因为可调用对象需要直接嵌入到std::function
-replacement对象的存储中。
从上面的例子可以看出这个问题。它们都没有这样的参数。因此,其中一个替代品不是拥有的,另一个不是静态分配的,他们不可能同时拥有这两个。
要测试lambda是否为无状态,您需要将is_stateless
应用于lambda表达式的类型,例如
auto lambda = [&args...](Func v, int& ret) { ret = v(args...); };
CHECK_EQUAL(true, is_stateless<decltype(lambda)>::value);
您正在将is_stateless
应用于一个根本不是lambda的类型。