1

I have written the following code, which plays with functions of type function<int(int)>. The functions compose, print, inc and guarded are helpers which combine other functions or produce some external effect. Then I use them to build my programs:

/* start of the program */
function<int(int)> recursion();

function<int(int)> go =
  compose(guarded(10, recursion()), compose(inc, print("go")));

function<int(int)> recursion() {
  return compose(go, print("recursion"));
}

However, when calling recursion()(0), an exception std::bad_function_call was thrown when go was reached the second time but I don't see why. Is there any dangling reference or empty std::function? Moreover, eta-expanding go works:

function<int(int)> go = [](int n) -> int {
  return compose(guarded(10, recursion()), compose(inc, print("go")))(n);
};

What's wrong with the original code? Why does the alternative one work?

Full code:

#include <string>
#include <iostream>
#include <functional>

using namespace std;

/* helper functions, some combinators */

//composing two functions, f1 . f2
function<int(int)> compose(const function<int(int)>& f1, const function<int(int)>& f2) {
  return [f1,f2](int n) -> int {
    return f1(f2(n));
  };
}

function<int(int)> print(const string& msg) {
  return [msg](int n) -> int {
    cout << "print: " << msg << endl;
    return n;
  };
}

function<int(int)> inc = [](int n) -> int {
  cout << "in inc lambda: " << n << endl;
  return n+1;
};

//calls the given function `f` only when `n` is less then `m`
function<int(int)> guarded(int m, function<int(int)> f) {
  auto g = [m,f](int n) -> int { return n<m? f(n) : m; };
  return compose(g, print("guarded"));
}

/* start of the program */
function<int(int)> recursion();

function<int(int)> go =
  compose(guarded(10, recursion()), compose(inc, print("go")));

function<int(int)> recursion() {
  return compose(go, print("recursion"));
}

int main() {
  try {
    recursion()(0);
  } catch (bad_function_call e) {
    cout << "bad_function_call: " << e.what() << endl;
  }
  return 0;
}
4

1 回答 1

6

在您的原始代码中,recursion()go. recursion本身尝试使用 的值go,但此时go尚未初始化,导致问题。

在替代代码中, 的初始化go仅将 lambda 分配给go而不调用recursion. recursion稍后调用时,go将已经被初始化。

于 2013-05-27T15:03:19.127 回答