我
我有以下代码试图以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
行,编译器会按预期抛出错误。但是,如果 var7
或 var8
的调用未被注释,则代码通过编译,但在运行时会触发随机分段错误或总线错误。代码在构建 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);
});
};
}
那么,到底是什么?
管道实现具有未定义的行为。它通过引用捕获所有内容,管道的函数参数也是如此,这些参数在管道函数结束后被销毁。通过复制 [=] 捕获,或通过引用传递到管道。