从lambda中的调用函数返回

时间:2017-07-31 22:06:18

标签: c++ c++11 lambda macros syntactic-sugar

Lambda是在函数/方法中创建可重用代码而不会污染父类的一种很棒的方法。它们在大多数时候都是C风格宏的非常实用的替代品。

但是,有一些来自宏的语法糖,我似乎无法用lambda复制,这就是从包含函数退出的能力。例如,如果我需要在检查一系列int的范围时返回,我可以使用宏轻松地做到这一点:

const int xmin(1), xmax(5);
#define CHECK_RANGE(x) { if((x) < xmin || (x) > xmax) return false; }

bool myFunc(int myint) {
    CHECK_RANGE(myint);
    int anotherint = myint + 2;
    CHECK_RANGE(anotherint);
    return true;
}

显然这是一个过于简单的例子,但基本的前提是我在不同的变量上反复执行相同的检查,我认为封装检查和相关的退出更具可读性。不过,我知道macros aren't very safe,特别是当他们变得非常复杂时。但是,据我所知,尝试做等效的lambda需要尴尬的额外检查,如下所示:

const int xmin(1), xmax(5);
auto check_range = [&](int x) -> bool { return !(x < xmin || x > xmax); };

bool myFunc(int myint) {
    if(!check_range(myint)) return false;
    int anotherint = myint + 2;
    if(!check_range(anotherint)) return false;
    return true;
}

有没有办法用lambda做到这一点?或者我错过了一些替代解决方案?

修改:我认为returning from inside a macro is generally a bad idea除非significant precautions are taken。我只是想知道是否可能。

4 个答案:

答案 0 :(得分:3)

你是对的 - 没有办法从lambda里面的来电回来。由于可以捕获并存储lambda以便稍后从任意调用者内部调用,这样做会导致不可预测的行为。

class Foo
{
    Foo(std::function<void(int)> const& callMeLater) : func(callMeLater) {}
    void CallIt(int* arr, int count)
    {
        for (index = count; index--;)
            func(count);
        // do other stuff here.
    }
    std::function<void(int)> func;
};

int main()
{
    auto find3 = [](int arr) 
    {
        if (arr == 3)
            return_from_caller; // making up syntax here.
    };

    Foo foo(find3);
};

答案 1 :(得分:1)

没有更好的方法来做这个,而不仅仅是使用lambda的返回值,然后使用调用函数中的return。宏是这样的。

就像C ++一样,这是退出使用另一个条件确定是否退出的函数的惯用方法。

答案 2 :(得分:1)

  

有没有办法用lambda做到这一点?

不完全像宏,但你的lambda,而不是返回bool,可以throw一个特殊的例外(类型bool,例如)

auto check_range
   = [](int x) { if ( (x < xmin) || (x > xmax) ) throw bool{false}; };

并且函数myFunc()可以截取此特殊类型

bool myFunc (int myint)
 {
   try
    {
      check_range(myint);
      int anotherint = myint + 2;
      check_range(anotherint);
      return true;
    }
   catch ( bool e )
    { return e; }
 }

对于单个check_range()电话,这是(我想)一个坏主意;如果你有很多电话,我想可能会很有趣。

以下是一个完整的工作示例

#include <iostream>

constexpr int xmin{1}, xmax{5};

auto check_range
   = [](int x) { if ( (x < xmin) || (x > xmax) ) throw bool{false}; };

bool myFunc (int myint)
 {
   try
    {
      check_range(myint);
      int anotherint = myint + 2;
      check_range(anotherint);
      return true;
    }
   catch ( bool e )
    { return e; }
 }

int main ()
 {
   std::cout << myFunc(0) << std::endl; // print 0
   std::cout << myFunc(3) << std::endl; // print 1
   std::cout << myFunc(7) << std::endl; // print 0
 }

答案 3 :(得分:0)

不是C ++ 11,但人们已经破解了C ++ 2a协程,基本上就是这样做了。

看起来有点像:

co_await check_range(foo);

其中co_await关键字表示在某些情况下,此协程可能会提前返回不完整的结果。在您的情况下,这个不完整的结果将是不可再造的错误。

我看到的游戏是选项,并且需要使用共享的ptr,但事情可能会在标准化之前得到改善。