特にループで、新しいC ++ 11の「自動」機能を使用する必要がありますか?


20

auto特にforループでキーワードを使用することの長所と短所は何ですか?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

マップのイテレータがあるのか、オブジェクトのプロパティを使用するのfirstか、secondまたは単にプロパティに直接アクセスするのかがわからない場合に、イテレータがあるかどうかがわからないようです。

これは、キーワードを使用するかどうかに関するC#の議論を思い出させますvar。私がこれまでに得ている印象は、C ++の世界autovarは、C#の世界よりも少ない戦いで人々がキーワードを採用する準備ができているということです。私にとって最初の本能は、変数の型を知りたいので、その変数に対して実行できる操作を知ることができるということです。


3
待つ!使用するvarかどうかについての戦いがあった?私は逃しました。
pdr

21
さらに良いことに、あなただけ使用することができますfor (auto& it : x)(あなたがコピーしたい場合や、参照なし)
タマシュSzelei

7
の内容を反復処理するループを作成していて、その内容がxわからない場合xは、そもそもループを作成しないでください
;

@fish:範囲ベースのforループルールですが、私は独創的で完了しているでしょう:範囲ベースのforループを使用する場合は、代わりに 'for(T&it:x)'を使用します。私の心の中で自動車の誤用のようなもの。
マルティエット

varを使用した戦いは、特に振り返ってみると少しばかげていました。カーゴカルトプログラミングを参照してください。
クレイグ

回答:


38

C ++の動機はより極端です。メタプログラミングなどにより、型はC#型よりもはるかに複雑で複雑になる可能性があるためです。auto明示的な型よりも読み書きが高速であり、より柔軟/維持可能です。つまり、入力を開始しますか

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

それは完全なタイプではありません。いくつかのテンプレート引数を逃しました。


8
例では+1ですが、それは「最新」のC ++の状態についても伝えます。
zvrba

22
@zvrba:ええ、汎用機能はC#よりもはるかに強力です。
DeadMG

4
それがtypedefの目的です
-gbjbaanb

19
@gbjbaanbいいえ、それautoが目的です。意図的に。typedef役立ちますがauto、さらに役立ちます。
コンラッドルドルフ

1
typedefが「本当に長いタイプの自動なりますを使用していない」という主張を無効にする
マイケル・

28

あなたの例では:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

xvisibleの宣言が必要です。したがって、のタイプはit明らかである必要があります。のタイプがx明らかでない場合、メソッドが長すぎるか、クラスが大きすぎます。


7
また、xコンテナにとって非常に悪い変数名です。状況によっては、おそらく(意味的に価値のある)名前を見て、可能な操作を推測することができます。
マックス

@Max:x一般的な例としてのみ使用されますが、かなりわかりやすい変数名を使用する傾向があります。
ユーザー

@Userもちろん、それが実世界の例だとは思いませんでした;)
マックス

14

異議!ロードされた質問。

3番目のコードに含ま??れているのに、1番目と2 番目のコードには含まれていない理由を説明できますか?公平を期すために、コード次のように読む必要があります。

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

そこ。を使用しなかったとしても同じ問題auto

そして、すべての場合において、答えは同じです:コンテキストが重要です。コードの一部について単独で有意義に話すことはできません。テンプレートを使用せず、具体的な型を使用した場合でも、コードの読者はその型の宣言について知る必要があるため、これは問題を別の場所に移動するだけです。

使用した場合auto、これらの状況では、コードが読めないのレンダリング、あなたのコード設計で何か間違っがあることを警告サインとして扱う必要があります。もちろん、ビット操作やレガシーAPIを扱う場合など、低レベルの詳細が重要な場合があります。その場合、明示的な型が読みやすさを高める場合があります。しかし、一般的に–いいえ。

var(明示的に言及しているので)に関して、C#コミュニティにを使用することに関して広大なコンセンサスもあります。その使用に対する議論は、一般的に誤 generallyに基づいています。var


1
ポイントは、自動で次に何を置くかわからないということだと思います...それはコード固有の「何か」か、メソッド「何か」を持つデータオブジェクトに到達するためのデータ型関連のアンパックですか
マイケルショー

1
@Ptolemyそして、私のポイントは次のとおりです。他の2つのコードであなたはまた、次置くために何を(一般的に)知らない:Tとしてユーザに不透明としてありますauto。しかし、1つは問題ないはずですが、もう1つはそうではありません。それは意味がありません。OPの場合T、任意の型の代用です。実際のコードでは、テンプレート(for typename std::vector<T>::iterator…)またはクラスインターフェイスの使用が考えられます。どちらの場合でも、実際の型はユーザーから隠されていますが、問題なくそのようなコードを定期的に記述しています。
コンラッドルドルフ

1
実際、そうです。それがベクトルの場合、あなたがする必要があることを知っている->そしてあなたはあなたのデータ型にアクセスすることができます。マップの場合、実行する必要があることがわかっている-> second->で、データ型にアクセスできますが、自動の場合、データ型にアクセスするために何をする必要があるかわかりません。「STLコレクションに含まれるデータ型とは」と「どのSTLコレクション型がありますか」を混同しているようです。autoはこの問題を悪化させます。
マイケルショー

1
@Ptolemyこれらの引数はすべて、を使用する場合と同じように真autoです。xコンテキストからサポートされる操作を確認するのは簡単です。実際、このタイプは追加情報を提供しませ。いずれの場合も、サポートされている操作のセットを伝えるために、いくつかのセカンダリ(IDE、ドキュメント、知識/メモリ)が必要です。
コンラッドルドルフ

1
つまり@Ptolemy だけあなたは何を知っていないことを非常に回旋状況にある場合にtrue beginを返しますが、あなたがないものを知ってstd::vector<>::iteratorいます。そして、この情報を簡単に提供できない悪いプログラミングツールを使用する必要があります。これは非常に複雑です。実際には、両方beginを知っているか、どちらも知ってiteratorいないため、関連情報をすぐに利用できるIDEまたはエディターを使用する必要があります。現代のすべてのIDEとプログラミングエディターはそれを行うことができます。
コンラッドルドルフ

11

プロ

あなたのコード:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

テンプレートに依存する名前のため、コンパイルされません。

これは正しい構文です:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

次に、型宣言の長さを確認します。これにより、autoキーワードが導入された理由がわかります。この :

for( auto it = x.begin(); it != x.end(); i++)

より簡潔です。だから、これはプロです。


CON

少し注意する必要があります。キーワードautoを使用すると、宣言した型を取得できます。

例えば ​​:

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

結論:はい、そうすべきですが、使いすぎないでください。次の例のように、それを使いすぎて、どこにでも自動配置する人もいます。

auto i = 0;

int i = 0;

auto i = 0。有罪。私がする。しかし、それ0はtypeのリテラルであることを知っているからintです。(および8進定数
;

6

はい、そうすべきです!autoタイプは消去されません。何x.begin()が「わからない」場合でも、コンパイラはその型を誤って使用しようとするとエラーを認識し、報告します。また、エミュレートすることは珍しいことではないmapvector<pair<Key,Value>>使用したコードはので、auto両方の辞書の表現のために動作します。


4

はい、autoデフォルトのルールとして使用する必要があります。型を明示的に指定するよりも生の利点があります。

  • コンパイラがすでに認識しているものを入力することはありません。
  • これにより、変数のタイプが戻り値のタイプの変更に「追従」します。
  • そうすることで、ローカル変数の初期化における暗黙的な変換とスライスのサイレント導入を防ぎます。
  • テンプレート内のいくつかの明示的な型計算の必要がなくなります。
  • 長い名前の戻り型を指定する必要がなくなります。(コンパイラ診断からコピーアンドペーストするもの)

ここで選択できます。また、選択肢がない場合もあります。

  • ラムダ型のような発言できない型の変数の宣言を許可します。

何をするかを正確に知っていればauto、デメリットはありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.