私の実際の問題はもっと複雑で、ここでそれを再現するための短い具体的な例を示すことは非常に難しいようです. したがって、関連する可能性のある別の小さな例をここに投稿しています。その議論は、実際の問題にも役立つ場合があります。
// A: works fine (prints '2')
cout << std::get <0>(std::get <1>(
std::forward_as_tuple(3, std::forward_as_tuple(2, 0)))
) << endl;
// B: fine in Clang, segmentation fault in GCC with -Os
auto x = std::forward_as_tuple(3, std::forward_as_tuple(2, 0));
cout << std::get <0>(std::get <1>(x)) << endl;
実際の問題には が含まれていないstd::tuple
ため、例を独立させるために、カスタムの最小限の大まかな同等物を次に示します。
template <typename A, typename B>
struct node { A a; B b; };
template <typename... A>
node <A&&...> make(A&&... a)
{
return node <A&&...>{std::forward <A>(a)...};
}
template <typename N>
auto fst(N&& n)
-> decltype((std::forward <N>(n).a))
{ return std::forward <N>(n).a; }
template <typename N>
auto snd(N&& n)
-> decltype((std::forward <N>(n).b))
{ return std::forward <N>(n).b; }
これらの定義を考えると、まったく同じ動作になります。
// A: works fine (prints '2')
cout << fst(snd(make(3, make(2, 0)))) << endl;
// B: fine in Clang, segmentation fault in GCC with -Os
auto z = make(3, make(2, 0));
cout << fst(snd(z)) << endl;
一般に、動作はコンパイラと最適化レベルに依存するようです。デバッグしても何もわかりませんでした。すべての場合において、すべてがインライン化および最適化されているように見えるため、問題の原因となっている特定のコード行を特定できません。
それらへの参照がある限り一時変数が存続することになっている場合 (関数本体内からローカル変数への参照を返さない場合)、上記のコードが問題を引き起こす可能性がある根本的な理由と、ケース A とB は異なるはずです。
私の実際の問題では、Clang と GCC の両方で、最適化レベルに関係なく、ワンライナー バージョン (ケース A) でもセグメンテーション エラーが発生するため、問題は非常に深刻です。
代わりに値または右辺値参照 (たとえばstd::make_tuple
、またはnode <A...>
カスタム バージョン) を使用すると、問題はなくなります。タプルがネストされていない場合も消えます。
しかし、上記のどれも役に立ちません。私が実装しているのは、ビュー用の一種の式テンプレートと、タプル、シーケンス、および組み合わせを含む多数の構造に対する遅延評価です。したがって、一時変数への右辺値参照が絶対に必要です。入れ子になったタプル、たとえば(a, (b, c))
、入れ子になった操作を含む式、たとえば、すべてが正常に機能しますu + 2 * v
が、両方ではありません。
上記のコードが有効かどうか、セグメンテーション違反が予想されるかどうか、それを回避する方法、コンパイラと最適化レベルで何が起こっているのかを理解するのに役立つコメントをいただければ幸いです。