この質問で、ハワード・ヒナントは言った
std :: tupleの一部の実装では、再帰的継承を使用します。しかし、良いものはそうではありません。;-)
誰かがそれに光を当ててくれませんか?
非再帰的な実装では、コンパイル時のパフォーマンスが向上します。信じられないかもしれませんが、のような頻繁に使用されるライブラリ機能std::tuple
では、実装方法が(良くも悪くも)クライアントに表示されるコンパイル時間に影響を与える可能性があります。再帰的な実装は、再帰の深さにおいて線形である(またはさらに悪化する可能性がある)コンパイル時間を生成する傾向があります。
これは、タプル自体のインスタンス化だけではありません。 std::get<I>(tuple)
たとえば、ある実装では線形のコンパイル時間がかかり、別の実装では一定のコンパイル時間がかかります。タプルのタプルを処理する場合、この影響は急速に悪化する(または悪化しない)可能性があります。つまり、再帰的な実装では、非再帰的な実装がまだO(1)であるのに、O(N ^ 2)のコンパイル時間が発生する可能性があります。
Fwiw、libc ++実装は、クライアントによって指定された順序でオブジェクトを配置しますが、コンパイラーの空の基本クラス最適化機能を使用して、空のコンポーネント用のスペースを最適化します。
アンドレイ・アレキサンドレスのGoingNative 2012の話を正確に思い出せませんが、彼はこの点について話しました。彼が言及した点の1つは、メモリのレイアウトでした。を持っている場合std::tuple<int, short, char, char>
、それはとしてメモリにchar, short, int
あり、このレイアウトは(私のシステムでは)としてレイアウトされている場合よりも4バイト多くかかりますint, short, char
。 R. Martinho Fernandesは、パディングを最小限に抑える順序でこれらをメモリ内で順序付けるのが最善の方法であることを私に思い出させました。これは、与えられた順序でも逆の順序でもありません。(ナイーブ継承は逆の順序になります)。
を書くstd::tuple<int, char, short, char>
と、ナイーブな継承によって機能するタプルはchar, short, int
、最適なパディングが0バイトの場合に、3バイトのパディングを使用して、これらをメモリ内の順序に配置します。(int, short, char, char
またはchar, char, short, int
)。
私がパディングについてであると仮定すると、R。Martinho Fernandesは、「[私の議論]は、実際の実装に最適な順序で再帰的継承を使用することを排除するものではありません。」と述べたので、そのナイーブな継承を指定します。悪い。
(メモリ内の順序は、別のオブジェクトを提供することを意味するものではありませんget<0>
。R。Martinho Fernandesは、順序はユーザーには表示されないようにする必要があると正しく指摘しています。ただし、GoingNativeイベントから思い出したように、これらはポイントでした。)
ビデオはhttp://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadicにあり、スライドはhttp://ecn.channel9.msdn.com/events/GoingNative12/にあります。 GN12VariadicTemplatesAreFunadic.pdf。
基本クラスのチェーンを使用しない理由の1つは、コンストラクターのチェーンが含まれていないことです。引数は適切なサブオブジェクトに直接転送されます。また、非再帰的な実装では、コンパイラへの負担が大幅に軽減され、[内部]シンボルの作成も大幅に削減されるようです。言うまでもなく、基本クラスのチェーンを使用しない方が実際には簡単です。