lambda函数的类型,使用auto

问题描述 投票:7回答:3

我正在尝试编写一个c ++ lambda函数,并且不喜欢使用auto作为类型。目前它看起来像:

#include <iostream>

int main() {
//  Sends the address of an integer to a function which prints out the contents;
    auto print_int = [](int* a) {std::cout << *a << std::endl;};
    int a;
    a = 3;
    print_int(&a);
    return 0;
}

但是,我想将auto改为std::function<void(int)>,但不确定如何。答案

似乎相关,但我不知道如何适应它。谢谢。

c++ c++11 lambda types
3个回答
7
投票

Lambdas旨在与auto或作为模板参数一起使用。你永远不知道lambda的类型,你不能输入它。每个lambda都有自己独特的类型。即使您知道该类型的名称,它们的类型名称通常也包含类型名称中禁止的字符。

为什么lambda有自己的类型?因为实际上,编译器创建了一个类似于这样的类:

struct /* unnamed */ {

    // function body
    auto operator()(int* a) const {
        std::cout << *a << std::endl;
    }

} print_int; // <- instance name

这段代码非常接近等价(我省略了转换运算符)。如您所见,您已经使用auto,因为lambdas正在推断返回类型。

有人会说使用std::function<void(int*)>,但我不同意。 std::function是一个围绕任何可调用的多态包装器。由于lambdas是可调用类型,因此它们适合它。换句话说,它的工作方式与std::any非常相似,但有一个呼叫操作员。它会在您的应用程序中产生开销。

那你该怎么办?

使用autoauto也不错。事实上,它甚至可以使您的代码更快,并减少不必要的打字。如果你对auto感到不舒服,那么你不应该! auto很棒,特别是如果你没有选择;)

实际上,您可以通过使用模板参数来避免使用auto

template<typename F, typename Arg>
void parametric_print(F function, Arg&& arg) {
    function(std::forward<Arg>(arg));
}

然后像这样使用它:

int main() {
    int a = 3;
    parametric_print([](int* a) {std::cout << *a << std::endl;}, &a);
}

你去,没有auto!但是,使用与auto相同的规则推导出模板参数。实际上,概念被C ++ 20标准接受,具有简洁的功能模板。您可以像这样编写相同的函数模板:

// C++20
void parametric_print(auto function, auto&& arg) {
    function(std::forward<decltype(arg)>(arg));
}

正如Oktalist所提到的,如果标准中接受了概念,那么你可以用auto替换Callable

Callable print_int = [](int* a) { std::cout << *a << std::endl; };

但它不会产生不同的类型,它只是在推断类型时强制执行一些规则。


2
投票

干得好:

int a;
[](int* a) {std::cout << *a << std::endl;}(&a);

没有使用auto


但是,我想将汽车更改为像std::function<void(int)>,但我不知道如何。

这当然是可能的。 std::functional有一个模板化的转换构造函数。你只需将lambda传递给构造函数,这就是它的全部内容。此外,你需要修复参数类型,因为你的lambda期望int*,而不是int(这是auto自动修复的那种bug)。

std::function<void(int*)> print_int = [](int* a) {std::cout << *a << std::endl;};

但请注意,这有两个缺点。

  • std::function包装器是一个隐藏可调用对象的实际类型的间接层。此包装层会增加运行时开销并阻止某些优化。
  • 如果更改返回值或lambda的参数,则必须手动更新类型。

1
投票

lambda有自己的未命名类型。

你可以将你的lambda转换成std::function<void(int*)> (或无捕捉的lambda到void (*)(int*))。

您可以显式创建您的仿函数,以便为其命名,例如:

class Print_int
{
public:
    void operator()(int* a) const {std::cout << *a << std::endl;}
};

然后

Print_int print_int;
© www.soinside.com 2019 - 2024. All rights reserved.