测试 lambda 是否为无状态
Test if a lambda is stateless?
我将如何测试lambda是否是无状态的,也就是说,它是否捕获了任何东西?我的猜测是将重载分辨率与函数指针重载一起使用,还是模板专用化?
int a;
auto l1 = [a](){ return 1; };
auto l2 = [](){ return 2; };
// test l1 and l2, get a bool for statelessness.
根据标准,如果 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;
};
这是测试代码:
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";
}
输出:
false
true
false
在线演示。
#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) );
不适用于多态 lambda,要求参数为闭包类型作为先决条件。(例如 is_captureless_lambda<int>
是std::true_type
。
根据 § 5.1.2/6
没有 lambda 捕获的非泛型 lambda 表达式的闭包类型具有公共非虚拟非显式 const 函数,以指向具有C++语言链接 (7.5) 的函数的指针,该函数具有与闭包类型的函数调用运算符相同的参数和返回类型。此转换函数返回的值应是函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果。对于没有 lambda 捕获的通用 lambda,闭包类型具有指向函数指针的公共非虚拟非显式 const 函数模板。
如果它可以转换为指向函数的指针,那么也许它必须不捕获任何内容(无状态)。在行动中:
int v = 1;
auto lambda1 = [ ]()->void {};
auto lambda2 = [v]()->void {};
using ftype = void(*)();
ftype x = lambda1; // OK
ftype y = lambda2; // Error
您还可以使用std::is_convertible
:
static_assert(is_convertible<decltype(lambda1), ftype>::value, "no capture");
static_assert(is_convertible<decltype(lambda2), ftype>::value, "by capture");
一个选项可能是显式查看类型的大小,无状态原则上应该与其他无状态类型具有相同的大小(我为引用类型选择了std::true_type
)。
#include<cassert>
#include<type_traits>
template<class T>
struct is_stateless_lambda : std::integral_constant<bool, sizeof(T) == sizeof(std::true_type)>{};
int main(){
auto l1 = [a](){ return 1; };
auto l2 = [](){ return 2; };
auto l3 = [&a](){ return 2; };
assert( boost::is_stateless_lambda<decltype(l1)>::value == false );
assert( boost::is_stateless_lambda<decltype(l2)>::value == true );
assert( boost::is_stateless_lambda<decltype(l3)>::value == false );
}
我不知道这个解决方案的便携性如何。无论如何,请检查我的其他解决方案:https://stackoverflow.com/a/34873139/225186
Boost.TypeTraits is_stateless
似乎出于某种原因完成了这项工作,没有太多戏剧性:
#include<boost/type_traits.hpp>
#include<cassert>
int main(){
auto l1 = [a](){ return 1; };
auto l2 = [](){ return 2; };
auto l3 = [&a](){ return 2; };
assert( boost::is_stateless<decltype(l1)>::value == false );
assert( boost::is_stateless<decltype(l2)>::value == true );
assert( boost::is_stateless<decltype(l3)>::value == false );
}
boost::is_stateless
其他条件的组合很简单,我想可以用标准类型特征来表示:
::boost::is_stateless =
::boost::has_trivial_constructor<T>::value
&& ::boost::has_trivial_copy<T>::value
&& ::boost::has_trivial_destructor<T>::value
&& ::boost::is_class<T>::value
&& ::boost::is_empty<T>::value
http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/is_stateless.html
根据sizeof
检查我的其他答案:https://stackoverflow.com/a/34873353/225186
- boost 是否有按特殊类型值编码状态"compact optional"?
- 检查两个节点在子节点上是否具有相同状态的更优雅的方法
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 是否很好地使用状态模式来维护当前选定的对象?
- GCC9是否允许避免std::变量的无值状态
- 如何确定boost msm中的特定状态是否为活动状态
- grpcc++异步服务器示例,在处理状态下是否需要互斥
- 验证(使用 static_assert)元组类型是否遵循某种顺序(有状态编译时检查)
- 对于每个线程,random_device是否以不同的状态启动?
- 对无状态派生类进行切片是否安全?
- 检测是否按下了某个键,而不是检测它是否始终处于关闭状态
- 检查特定应用程序的窗口是否处于最小化状态
- 如何在C API中检查MySql连接是否处于活动状态
- 类的堆分配对象是否在其作用域之后但在 C++ 中调用其析构函数之前处于活动状态
- HTTP响应标头是否可以不以状态行开头
- mutex::lock() 检查一次解锁状态是否已经被另一个线程锁定?
- pclose() 返回管道的终止状态是否在所有平台上都向左移动了 8 位?
- c++ 14中语句(void)f()的状态是否格式错误?如果不是,f()部分是否为丢弃值
- 检测表单中任何小部件的状态是否发生了变化
- 存储可移动物体的"有效性"状态是否是一种好的做法?