如何在C++中使用空 Lambda?
How Can I use Null Lambda in C++?
我想声明一个这样的函数:
template <typename Lambda>
int foo(Lambda bar) {
if(/* check bar is null lambda */)
return -1;
else
return bar(3);
}
int main() {
std::cout << foo([](int a)->int{return a + 3;}) << std::endl;
std::cout << foo(NULL_LAMBDA) << std::endl;
}
那么,如何声明NULL_LAMBDA
和条件检查传递的lambda函数是否为空?
您可以添加专门的专业化:
#include <iostream>
#include <cstddef>
template<typename Lambda> int
foo(Lambda bar)
{
return(bar(3));
}
template<> int
foo<::std::nullptr_t>(::std::nullptr_t)
{
return(-1);
}
int main()
{
::std::cout << foo([] (int a) -> int {return(a + 3);}) << ::std::endl;
::std::cout << foo(nullptr) << ::std::endl;
}
在这种特殊情况下,您可以将 null 闭包定义为始终返回-1
的闭包
template <typename Lambda>
int foo(Lambda bar) {
return bar(3);
}
#include <iostream>
int main() {
auto const NULL_LAMBDA = [](int){ return -1; };
std::cout << foo([](int a) {return a + 3;}) << std::endl;
std::cout << foo(NULL_LAMBDA) << std::endl;
}
可能性是,如果您在运行时选择要传递的实现,那么最好使用std::function
而不是实例化模板来擦除它。 并且允许std::function
为空- 它可以从空指针分配并与空指针进行比较。
如果您在编译时知道某些调用站点将始终传递"null"lambda,那么您可以适当地专门化实现。 显而易见的选项包括使用不接受bar
参数的版本重载foo()
,或者在bar
不是可调用对象时将其专用于不同的实现。
如果foo()
的大部分内容对于这两种调用都是通用的(也许它有很多副作用,并且bar()
作为回调提供?(,那么您可以使用std::is_same<>
对可选部分进行条件化。 这需要if constexpr
,因为 lambda 不可调用为bar(3)
:
static auto const NULL_LAMBDA = nullptr;
#include <type_traits>
template <typename Lambda>
int foo(Lambda bar) {
if constexpr (std::is_same<decltype(bar), std::nullptr_t>::value)
return -1;
else
return bar(3);
}
#include <iostream>
int main() {
std::cout << foo([](int a) {return a + 3;}) << std::endl;
std::cout << foo(NULL_LAMBDA) << std::endl;
}
Lambda 是一类类型,而不是一种类型。
我们可以这样做:
struct null_callable_t{
template<class...Ts>
constexpr void operator()(Ts&&...)const{}
explicit constexpr operator bool()const{return false;}
constexpr null_callable_t() {}
friend constexpr bool operator==(::std::nullptr_t, null_callable_t ){ return true; }
friend constexpr bool operator==(null_callable_t, ::std::nullptr_t ){ return true; }
friend constexpr bool operator!=(::std::nullptr_t, null_callable_t ){ return false; }
friend constexpr bool operator!=(null_callable_t, ::std::nullptr_t ){ return false; }
};
constexpr null_callable_t null_callable{};
现在我们的代码变成:
template <typename Lambda>
int foo(Lambda bar) {
if(!bar)
return -1;
else
return bar(3);
}
这很流畅:
std::cout << foo([](int a) {return a + 3;}) << std::endl;
std::cout << foo(null_callable) << std::endl;
但是,我个人最喜欢的解决这个问题的方法是写function_view
。
它将指针和操作包装在一个有点像 std 函数的非分配事物中。 编译器非常擅长内联简单的函数指针,因此如果使方法内联,开销仍然很低。
请注意,在 C++17 中,我们可以这样写...
template<typename Lambda>
int foo(Lambda bar)
{
if constexpr (std::is_same_v<std::decay_t<Lambda>, std::nullptr_t>)
return -1;
else if constexpr (std::is_convertable_v<Lambda, bool>)
{
if (bar)
return bar(3);
else
return -1;
}
else
return bar(3);
}
我想在 C++20 中,我们可以定义一个概念,即 std::invocable(概念标头(或nulltpr_t来约束 Lambda。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 可组合的lambda/std::函数与std::可选
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 如何将lambda作为模板类的成员函数参数
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 在 lambda 捕获中声明的变量的类型推导
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 模板函数指针和lambda
- 两组使用lambda函数的大括号
- 使lambda不可复制/不可移动
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- 将带有unique_ptr的可变 lambda 传递给 const&std::function
- AWS Lambda C++运行时权限被拒绝
- 捕获lambda中的std::数组
- 这 4 个 lambda 表达式之间有什么区别?
- 在实现文件中使用头文件的通用 lambda
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?