如何在C++中使用Null Lambda?

Seo*_*ong 17 c++ lambda c++11

我想声明一个这样的函数:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后,我如何声明NULL_LAMBDA和条件检查传递lambda函数是否为null?

use*_*670 26

您可以添加专门的专业化:

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • @LWimsey具有模板特化可以在显式提供模板参数时调用正确的`foo`. (3认同)

Tob*_*ght 8

在这种特殊情况下,您可以将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;
}
Run Code Online (Sandbox Code Playgroud)

可能的情况是,如果您在运行时选择要通过哪个实现,那么使用std::function而不是实例化模板来进行类型擦除会更好.并且std::function允许a 为 - 可以从空指针进行分配和比较.


如果您在编译时知道某些调用站点将始终传递"null"lambda,那么您可以适当地专门化实现.明显的选项包括foo()使用不接受bar参数的版本进行重载,或者在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;
}
Run Code Online (Sandbox Code Playgroud)

  • Lambdas不支持`==`.除非偶然,否则双方都是具有相同签名的无捕捉lambdas并且您没有使用MSVC. (2认同)
  • 我根本不提``==`; 它是一种巨大的蠕虫病毒.它只是因为函数指针的转换函数而编译(这需要两边都是无捕获的).因为每个lambda表达式都会创建一个新的unmentionable类型,所以它非常脆弱:`foo([](int){return 0;})`可能会也可能不会触及`NULL_LAMBDA`路径. (2认同)