2012-03-01 9 views
9

for (auto x : expr)には暗黙のauto&& __range = exprが含まれているため、式テンプレートはC++ 11の範囲に基づいて壊れてしまいます。式テンプレートとC++での範囲指定11

表現テンプレートテンプレートクラスを作成する方法はありますか?それで、それらはどちらも正しく、または、少なくともコンパイルエラーをスローするために、レンジベースで正しく動作しますか?

基本的には、式テンプレートが正しくコンパイルされるが、参照がぶら下がって実行時に失敗する可能性を避けたいと思います。私は式テンプレートをラウンドベースで使用する前に何かにラップする必要はありません。ただし、ユーザーが式テンプレートをラップすることを忘れた場合、静かなランタイムエラーがない限り、テンプレートをラップする必要はありません。

+1

範囲ベースの 'for'ループの' auto && 'は本当に足で簡単に自分を撃ってしまうかもしれません - どの範囲の型が正確に影響を受けているのかはまだ分かりません。 non-const:危険な、非参照:問題のない、???)。 – Philipp

+1

@Philipp:「レンジタイプ」はありません。 "概念"の範囲に準拠した型があります。具体的には、入力イテレータを返す 'begin/end'オーバーライドのペアがあります。 –

+1

答えは、表現テンプレートが "概念"の範囲に合致しないこと、つまり 'begin'と' end'を持たないということです。 – Clinton

答えて

2

いくつかのオプションが考えられますが、それぞれ独自の醜さがあります。

明らかなオプションの1つは、参照の代わりにポインタ(おそらくunique_ptr)を使用することです。もちろん、これが動作するためには、ヒープからの割り当て、またはカスタムアロケータが必要です。良いアロケータでは、このアプローチにはいくつかメリットがあると思います。そして再び、演算子のオーバーロードはちょうど不快になるでしょう。

もう1つの方法は、const参照ではなく値でサブ式を格納することです。このアプローチの効率はコンパイラに依存しますが、基本的には一時的なものを扱っているので、現代のコンパイラではコピーを最適化できると思います。

最後のアプローチでは、コードに同じ構造を維持できますが、ユーザーは強制的に式を評価します。これは、式の基礎となる型(たとえば、std::vector<int>)である反復可能な型が1つだけ必要です。どの式クラスも、beginendのメソッドまたは関数を定義する必要はありませんが、基になる型に変換できるだけです。この方法では、for(auto x : expr)のようなコードはコンパイル時に失敗しますが(exprは反復不可能なので)、式がすでに評価されているので、for(auto x : static_cast<vector<int>>(expr))を書くことができます。

範囲ベースのforループを使用して式テンプレート操作を実装する場合は、エクスプレッションテンプレートクラスにbeginおよびendメソッドをプライベートまたはプロテクトして提供できます。各テンプレートクラスが他のテンプレートクラスのbeginおよびendメソッドにアクセスできることを確認してください。式テンプレートは関数のパラメータなので、この文脈では大丈夫です。その関数内でループを書くときに参照がぶら下がる心配はありません。

6

これについては一般的に何もできません。範囲として式を指定する場合は、forステートメントの初期化後に有効なものに解決する必要があります。コンパイル時に、特定の型がautoによって推測されたことを検出する方法はありません。

発現系をより移動ベースにすると、参照を保持する必要がなくなります。潜在的に死んでいるものへの参照を格納しようとするよりも、より安全な結果がautoで得られます。移動不可能なタイプのコピーで問題が発生した場合は、そのまま移動してください。

+2

それは問題を解決しません。範囲ベースのforループに暗黙の 'auto && __ range = listOfInt;'が含まれています。これは、 'listOfInt'が実際にいくつかの式テンプレートクラスの値だった場合に問題を引き起こす可能性があります。 –

+0

@リチャードスミス:それは本当です、私はその場合、明示的なキャストまたは新しい自動変数を導入することしかできないと思います。 – Philipp

関連する問題