CPSフォームでプロシージャを定義しようとする次のコードがあります。C++の上位関数からラムダが返されたときのセグメンテーションエラー
#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
の呼び出しがコメント解除されている場合、コードはコンパイルをパスしますが、実行時にランダムなセグメンテーションフォルトまたはバスエラーが発生します。コードはラムダを構築する間は安全ですが、ラムダを適用するとクラッシュします。
私の欠陥を指摘してくれてありがとう。
私がvar8
よう
var7 = pipe(var3, pipe(var3, var3));
にコードを変更した場合、それがうまく動作することを補完することが有用です。
私は驚いたことにランダムに試してみました。私はちょうど最初の宣言を保持し、最初のものをコピーして2番目のものを変更します:
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);
});
};
}
だから何?
「auto proc2s」を宣言して使用していない理由は何ですか? –
申し訳ありませんが、それはちょうどデバッグスタッフでした。編集されました。 – Cowsay