如何立即调用C++ lambda?

Sté*_*ane 13 c++ lambda c++11 c++14

我继承的类中的构造函数需要传入一个非平凡的对象.类似于:

MyFoo::MyFoo() : SomeBase( complexstuff )
{
    return;
}
Run Code Online (Sandbox Code Playgroud)

complexstuff与之无关MyFoo,所以我不想传递它.

而不是写一些返回的1-off临时函数complexstuff我使用了lambda.我花了几分钟才弄明白的是我必须调用 lambda.所以我的代码现在看起来像这样:

MyFoo::MyFoo() : SomeBase(
    []()
    {
        /* blah blah do stuff with complexstuff */
        return complexstuff;
    } () )
{
    return;
}
Run Code Online (Sandbox Code Playgroud)

如果你没有抓住它,它是微妙的.但是在lambda体之后,我不得不()告诉编译器立即"运行"lambda.在弄清楚我做错了什么之后才有意义.否则,如果没有()调用lambda,gcc会说类似于:

error: no matching function for call to 'SomeBase(<lambda()>)'
Run Code Online (Sandbox Code Playgroud)

但现在我有想法 - 我这样做了吗?在C++ 11或C++ 14中是否有更好的方法告诉编译器我希望它立即调用我编写的lambda?或者()像我通常的做法那样追加空洞?

Rak*_*111 14

但现在我有想法 - 我这样做了吗?

是的,你做到了.

在C++ 11或C++ 14中是否有更好的方法告诉编译器我希望它立即调用我编写的lambda?

从来没听说过.lambda也只是一个函数对象,所以你需要有一个()调用它,没有办法解决它(当然除了一些调用lambda的函数std::invoke).

如果你想要你可以删除()捕获列表之后,因为你的lambda不带任何参数.

或者()像我通常的做法那样追加空洞?

是的,这是最短的路.如前所述,std::invoke也可以工作,但它需要更多的打字.我会说直接打电话()是通常的做法.

  • 为了说明中间点,`[](){}`是一个空的lambda函数对象,而`[] {}()`是一个`void`表达式,它是通过计算空的lambda得到的. (5认同)

Hen*_*nke 8

在 C++17 中,您可以使用std::invoke. 这与您所做的完全相同,但也许您会发现这更清楚。

#include <iostream>
#include <functional>

void foo(int i)
{
  std::cout << i << '\n';
}

int main()
{
  foo( std::invoke( []() { return 1; } ) );
}
Run Code Online (Sandbox Code Playgroud)

  • 这是100%毫无意义的。`std::invoke` 用于通用代码,您可能会在其中获得函数对象、PMF、函数指针等。当您已经知道如何调用可调用对象时,`std::invoke` 除了减慢构建速度之外没有其他任何作用次。 (5认同)
  • @ildjarn `std::invoke` 在这里用来强调函数调用,而不是依赖 `()` 细节,阅读代码的人可能会错过这个细节。仅此一点就可以节省开发人员的时间。该技术在本书中进行了解释:https://www.bfilipek.com/2016/11/iife-for-complex-initialization.html#improving-readability-of-iife (3认同)
  • 它没有“做完全相同的事情”,它做了很多_更多_,因此增加了构建时间。你没有提到_那个_。;-] 这不仅仅是对 `std::invoke` 的滥用;即使在某些情况下主观上“更清晰”,但无论何时拥有固定形式的可调用对象,客观上都会更糟。 (2认同)

Sto*_*ica 7

没有办法告诉编译器立即调用 lambda。最简单的课程(在复杂性和键入字符数方面)是您已经完成的课程。对于任何使用过闭包语言的人来说,这也是非常惯用的(我在这里考虑的是 JavaScript)。

如果您想避免使用该语法,请修改SomeBasecomplexstuff执行可调用对象。


如果你想要的只是调用 lambda 的语法糖,你总是可以像 Alexandrescu 的 SCOPE_GUARD 那样做,并滥用运算符重载:

Live example

#include <iostream>

namespace detail {

enum class invoke_t{};

template<class Callable>
auto operator+(invoke_t, Callable c) -> decltype(c()) {
    return c();
}

}

constexpr detail::invoke_t invoke{};


int main() {
    invoke + []() {
        std::cout << "called";
    };
}
Run Code Online (Sandbox Code Playgroud)

但我不会。发明你自己的 DSL 只会让你的代码更难维护。坚持使用简单语言结构的习语。