测试std::函数的静态替换以获得非无状态lambda支持



查看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的类型。

最新更新