测试lambda是否是无状态的?

Ske*_*een 13 c++ lambda c++11 c++14

如果一个lambda是无状态的,也就是说,如果它捕获了任何东西,我将如何进行测试?我的猜测是使用带有函数指针重载或模板特化的重载解析?

int a;
auto l1 = [a](){ return 1; };
auto l2 = [](){ return 2; };
// test l1 and l2, get a bool for statelessness.
Run Code Online (Sandbox Code Playgroud)

Naw*_*waz 14

根据标准,如果lambda没有捕获任何变量,那么它可以隐式转换为函数指针.

基于此,我想出了一个is_stateless<>元函数,它告诉你lambda是否是无状态的.

#include <type_traits>

template <typename T, typename U>
struct helper : helper<T, decltype(&U::operator())>
{};

template <typename T, typename C, typename R, typename... A>
struct helper<T, R(C::*)(A...) const> 
{
    static const bool value = std::is_convertible<T, R(*)(A...)>::value;
};

template<typename T>
struct is_stateless
{
    static const bool value = helper<T,T>::value;
};
Run Code Online (Sandbox Code Playgroud)

这是测试代码:

int main() 
{
    int a;
    auto l1 = [a](){ return 1; };
    auto l2 = [](){ return 2; };
    auto l3 = [&a](){ return 2; };

    std::cout<<std::boolalpha<<is_stateless<decltype(l1)>::value<< "\n";
    std::cout<<std::boolalpha<<is_stateless<decltype(l2)>::value<< "\n";
    std::cout<<std::boolalpha<<is_stateless<decltype(l3)>::value<< "\n";
}
Run Code Online (Sandbox Code Playgroud)

输出:

false
true
false
Run Code Online (Sandbox Code Playgroud)

在线演示.

  • 请注意这里缺少一个重要的测试:即`is_lambda`(考虑:`struct poor_bastard {void operator()()const; operator void(*)(void*)()const; int haha​​_i_have_state_shut_up;};`) .还要注意这将不会有任何机会与即将到来的多态lambda一起工作. (7认同)
  • 没有捕获的lambda不一定是无状态btw,使得这个测试的结果比现在更加无价值.(考虑:`static int where_is_your_statelessness_now = 0; void bar(){auto f = [/*look ma,no captures!*/] {return ++ where_is_your_statelessness_now;}; ...}`) (7认同)
  • 仅仅因为lambda是无状态的,并不意味着它转换为指向函数的指针 - 考虑自动L = [](){return [=] {return 1; }; }; auto stateless = L(); 但无国籍者不会转换为fptr.只有没有任何显式,默认或初始捕获的lambda才能转换为fptr. (5认同)
  • @Skeen:为什么?这是特别感兴趣的特定信息吗?(不!)通过将其置于标准中而不是如上所述(在相当罕见的情况下)需要它来实现它可以获得任何东西吗?(再一次,不!)我认为Nawaz在满足OP的要求方面做得很好,但我认为在标准中加入类似的东西没有任何好处. (3认同)
  • IMO产生假阳性和假阴性的测试毫无价值. (3认同)
  • @Nawaz有人提到将来将它添加到标准中(没有特殊语法的多态函数对象并不是真的很新) (2认同)
  • 帖子没有答案,因为问题的整个前提是有缺陷的 - ***lambda不是特别的,不要为他们做特殊的事情***. (2认同)
  • @ R.MartinhoFernandes:我研究了无状态的*具体*含义.第一行问题是,*"如果一个lambda是无状态的,我将如何测试**,即如果它捕获任何东西**?"*.你没理睬吗? (2认同)

mas*_*oud 6

根据§5.1.2/ 6

没有lambda-capture的非泛型lambda表达式的闭包类型有一个公共的非虚拟非显式const转换函数指向函数,C++语言链接(7.5)具有相同的参数和返回类型.闭包类型的函数调用操作符.此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果.对于没有lambda-capture的通用lambda,闭包类型具有指向函数的公共非虚拟非显式const转换函数模板.

如果它是转化为函数指针,然后MAYBE它有没有捕获任何(无状态).在行动:

int v = 1;
auto lambda1 = [ ]()->void {};
auto lambda2 = [v]()->void {};

using ftype = void(*)();

ftype x = lambda1; // OK
ftype y = lambda2; // Error
Run Code Online (Sandbox Code Playgroud)

您还可以使用std::is_convertible:

static_assert(is_convertible<decltype(lambda1), ftype>::value, "no capture");
static_assert(is_convertible<decltype(lambda2), ftype>::value, "by capture");
Run Code Online (Sandbox Code Playgroud)


Luc*_*ton 6

#include <type_traits> // std::true_type, std::false_type
#include <utility>     // std::declval

template<typename Lambda>
auto is_captureless_lambda_tester(int)
-> decltype( +std::declval<Lambda>(), void(), std::true_type {} );

template<typename Lambda>
auto is_captureless_lambda_tester(long)
-> std::false_type;

template<typename Lambda>
using is_captureless_lambda = decltype( is_captureless_lambda_tester<Lambda>(0) );
Run Code Online (Sandbox Code Playgroud)

不适用于多态lambda,需要作为参数为闭包类型的前提条件.(例如is_captureless_lambda<int>std::true_type).