调用 lambda 时出现分段错误,从 C++11 中的高阶函数返回



我有以下代码试图以CPS形式定义过程。

#include <iostream>
#include <utility>
#include <type_traits>
#include <string>
using namespace std;

template <typename T> using Func = std::function<T>;
template <typename T> using Cont = Func<void (T &&)>;
template <typename T, typename U> using Proc = Func<void (T &&, Cont<U>)>;
template <typename T> struct RevProc;
template <typename T, typename U> struct RevProc<Proc<T, U>> {
  using ArgType = T;
  using RetType = U;
};
template <typename P1, typename P2> auto pipe(P1 proc1, P2 proc2)
  -> Proc<typename RevProc<P1>::ArgType, typename RevProc<P2>::RetType> {
  using T = typename RevProc<P1>::ArgType;
  using U = typename RevProc<P2>::ArgType;
  static_assert(is_same<U, typename RevProc<P1>::RetType>::value,
    "Mismatch procedure type.");
  using V = typename RevProc<P2>::RetType;
  return [&] (T &&t, Cont<V> pass) {
    proc1(move(t), [&] (U &&u) {
      proc2(move(u), pass);
    });
  };
}
template <typename P1, typename P2, typename... Ps> auto pipe(P1 proc1, P2 proc2, Ps ...procs)
  -> Proc<typename RevProc<P1>::ArgType, typename RevProc<decltype(pipe(proc2, procs...))>::RetType> {
  auto proc2s = pipe(proc2, procs...);
  return pipe(proc1, proc2s);
}
int main() {
  Func<void ()> var1;
  Cont<int> var2([] (int &&x) {});
  Proc<int, int> var3([] (int &&x, Cont<int> pass) {
    pass(x + 1);
  });
  auto var4 = pipe(var3, var3);
  var4(42, [] (int &&x) {
    cout << x << endl;
  });
  Proc<string, int> var5([] (string &&str, Cont<int> pass) {
    pass(str.length());
  });
  // auto var6 = pipe(var5, var5);
  Proc<int, int> var7 = pipe(var3, var3, var3);
  // var7(42, [] (int &&x) {
  //   cout << x << endl;
  // });
  auto var8 = pipe(var5, var3, var3);
  var8("something", [] (int &&x) {
    cout << x << endl;
  });
  return 0;
}

如果我取消注释var6行,编译器会按预期抛出错误。但是,如果 var7var8 的调用未被注释,则代码通过编译,但在运行时会触发随机分段错误或总线错误。代码在构建 lambda 期间是安全的,但在应用它们时会崩溃。

感谢您指出我的错误。


如果我将代码修改为

var7 = pipe(var3, pipe(var3, var3));

所以var8.


随机尝试并修复了它,令我惊讶。我只保留第一个声明,并通过复制第一个来修改第二个声明:

template <typename P1, typename P2, typename... Ps> constexpr auto pipe(P1 proc1, P2 proc2, Ps ...procs)
  -> Proc<typename RevProc<P1>::ArgType, typename RevProc<decltype(pipe(proc2, procs...))>::RetType> {
  using T = typename RevProc<P1>::ArgType;
  using U = typename RevProc<P2>::ArgType;
  static_assert(is_same<U, typename RevProc<P1>::RetType>::value,
    "Mismatch procedure type.");
  using V = typename RevProc<P2>::RetType;
  return [&] (T &&t, Cont<V> pass) {
    proc1(move(t), [&] (U &&u) {
      pipe(proc2, procs...)(move(u), pass);
    });
  };
}

那么,到底是什么?

管道实现具有未定义的行为。它通过引用捕获所有内容,管道的函数参数也是如此,这些参数在管道函数结束后被销毁。通过复制 [=] 捕获,或通过引用传递到管道。

相关内容

  • 没有找到相关文章

最新更新