如何定义is_lambda_that_captures类型特征检测捕获变量的Lambda?
解决C++17下检测捕获变量的Lambda的类型特征问题
嘿,这个问题我刚好有思路!在C++17里,我们可以利用无捕获lambda和有捕获lambda的一个关键差异来实现这个类型特征:无捕获的lambda可以隐式转换为对应的普通函数指针,而有捕获的lambda做不到。基于这个特性,我们可以构建出需要的is_lambda_that_captures类型特征。
下面是完整的可运行解决方案:
#include <type_traits> #include <functional> #include <iostream> // 辅助模板:从lambda的operator()成员函数指针中提取对应的普通函数指针签名 template <typename> struct get_function_signature; // 特化处理lambda的const operator()(大多数lambda默认是const的) template <typename Ret, typename Class, typename... Args> struct get_function_signature<Ret(Class::*)(Args...) const> { using type = Ret(*)(Args...); }; // 类型别名,简化使用 template <typename T> using get_function_signature_t = typename get_function_signature<decltype(&T::operator())>::type; // 主模板:默认假设类型不是捕获变量的lambda template <typename T, typename = void> struct is_lambda_that_captures : std::false_type {}; // SFINAE特化:当类型无法转换为对应的普通函数指针时,判定为捕获变量的lambda template <typename T> struct is_lambda_that_captures<T, std::enable_if_t<!std::is_convertible_v<T, get_function_signature_t<T>>>> : std::true_type {}; // 变量模板,简化调用(C++17特性) template <typename T> inline constexpr bool is_lambda_that_captures_v = is_lambda_that_captures<T>::value; int main(){ auto non_capture = [](){ std::cout<<"this lambda is not capturing!"<<std::endl; }; auto capture = [&](){ std::cout<<"this lambda is capturing"<<std::endl; }; // 原有的断言,验证无捕获lambda可转换为std::function static_assert(std::is_convertible_v<decltype(non_capture), std::function<void()>>, "message1"); // 目标断言:检测有捕获的lambda static_assert(is_lambda_that_captures_v<decltype(capture)>, "this is some error message"); // 额外验证:无捕获lambda不会被误判 static_assert(!is_lambda_that_captures_v<decltype(non_capture)>, "non-capture lambda should not be detected as capturing"); non_capture(); capture(); }
实现原理说明
get_function_signature模板:用来解析lambda的operator()成员函数指针类型,把它转换成对应的普通函数指针类型。比如,对于无捕获lambda的void(LambdaType::*)() const,会转换成void(*)()。is_lambda_that_captures类型特征:- 主模板默认返回
std::false_type,也就是默认认为类型不是捕获变量的lambda。 - 通过SFINAE(替换失败不是错误)的特化版本,当类型
T无法转换为对应的普通函数指针类型时,启用这个特化,返回std::true_type——这正是有捕获lambda的特征。
- 主模板默认返回
is_lambda_that_captures_v变量模板:C++17的变量模板特性,让我们可以直接用is_lambda_that_captures_v<T>代替is_lambda_that_captures<T>::value,代码更简洁。
注意事项
- 这个实现针对的是默认的const lambda(大多数lambda都是const的),如果你的lambda是mutable的,只需要给
get_function_signature增加一个特化版本,处理非const的operator()即可:template <typename Ret, typename Class, typename... Args> struct get_function_signature<Ret(Class::*)(Args...)> { using type = Ret(*)(Args...); }; - 这个类型特征也会对其他不能转换为普通函数指针的可调用类型返回
true,但如果你的使用场景只针对lambda,这个问题可以忽略。
内容的提问来源于stack exchange,提问作者Nikola Lozanovski
相关产品推荐
相关产品推荐

