複雑なテンプレート型用のC++ 11標準で利用可能な新しいauto
キーワードを使用してきました。しかし、私はそれを次のようなことにも使用しています:
auto foo = std::make_shared<Foo>();
より懐疑的に:
auto foo = bla(); // where bla() return a shared_ptr<Foo>
このトピックに関する議論はあまり見ていません。タイプは多くの場合、ドキュメントと健全性チェックの形式であるため、auto
は使い古されているようです。 auto
を使用してどこで線を引きますか。また、この新しい機能の推奨される使用例は何ですか?
明確にするために:私は哲学的な意見を求めていません。私は、標準委員会によるこのキーワードの意図された使用を、おそらくその意図された使用が実際にどのように実現されるかについてのコメントとともに求めています。
サイドノート:この質問はSE.Programmersに移動され、Stack Overflowに戻りました。これについての議論はこれで見つけることができます メタ質問 。
一目で型を書くのが難しいときはいつでもauto
キーワードを使うべきだと思いますが、式の右辺の型は明らかです。たとえば、次を使用します。
my_multi_type::nth_index<2>::type::key_type::composite_key_type::
key_extractor_Tuple::tail_type::head_type::result_type
int
であることがわかっていても、boost::multi_index
の複合キータイプを取得します。将来変更される可能性があるため、単にint
と書くことはできません。この場合、auto
と書きます。
したがって、auto
キーワードが特定のケースで読みやすさを改善する場合は、それを使用します。読者にとってauto
が表すタイプが明らかな場合は、auto
と書くことができます。
ここではいくつかの例を示します。
auto foo = std::make_shared<Foo>(); // obvious
auto foo = bla(); // unclear. don't know which type `foo` has
const size_t max_size = 100;
for ( auto x = max_size; x > 0; --x ) // unclear. could lead to the errors
// since max_size is unsigned
std::vector<some_class> v;
for ( auto it = v.begin(); it != v.end(); ++it )
// ok, since I know that `it` has an iterator type
// (don't really care which one in this context)
auto
可能な限りどこでも、特にconst auto
を使用して、副作用の心配を減らします。明らかな場合を除き、型について心配する必要はありませんが、静的に検証されるため、繰り返しを避けることができます。 auto
を実行できない場合、decltype
を使用して、式に基づいてcontractsとして型を意味的に表現できます。コードは異なって見えますが、前向きな変化になります。
簡単です。 do n't careタイプの場合に使用します。例えば
for (const auto & i : some_container) {
...
ここで気になるのは、i
がコンテナ内にあるものであるということだけです。
Typedefに少し似ています。
typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
ここでは、h
とw
がfloatであるかdoubleであるかは関係なく、高さと重量を表現するのに適したタイプのみです。
または考慮する
for (auto i = some_container .begin (); ...
ここで私が気にするのは、それがoperator++()
をサポートする適切なイテレータであるということです。
また、ラムダのタイプは綴ることができないので、auto f = []...
は良いスタイルです。別の方法はstd::function
にキャストすることですが、これにはオーバーヘッドが伴います。
私はauto
の「乱用」を本当に想像することはできません。私が想像できる最も近いのは、何らかの重要な型への明示的な変換を自分自身から奪うことですが、そのためにauto
を使用せずに、目的の型のオブジェクトを構築します。
can副作用を引き起こすことなくコードの冗長性を削除する場合、mustそうすることをお勧めします。
反例(他の人の答えから借用):
auto i = SomeClass();
for (auto x = make_unsigned (y); ...)
ここでは、型が何であるかを気にするので、Someclass i;
とfor(unsigned x = y;...
を記述する必要があります。
頑張れ。 auto
を使用すると、コードの記述が簡単になります。
あらゆる言語のすべての新機能は、少なくとも一部のタイプのプログラマーによって過剰に使用されます。一部の経験豊富なプログラマー(初心者ではない)による中程度の過剰使用によってのみ、残りの経験豊富なプログラマーが適切な使用の境界を学習します。通常、極端な過剰使用は悪いことですが、そのような過剰使用は機能の改善またはそれを置き換えるより良い機能につながる可能性があるため、良い可能性があります。
しかし、次のような数行以上のコードで作業している場合
auto foo = bla();
タイプが0回示されている場合、これらの行を変更してタイプを含めることができます。最初の例は、型が1回記述されているため素晴らしいです。auto
を使用すると、面倒なテンプレート型を2回記述する必要がなくなります。 Hooray for C++++。しかし、近くの行で簡単に表示されない場合、タイプを明示的にゼロ回表示すると、少なくともC++とそのすぐ後継で、私は緊張します。抽象化、多態性、汎用性を高めて、より高いレベルで動作するように設計された他の言語については、問題ありません。
はい、読みやすさを損なうほど使いすぎる可能性があります。正確な型が長い、発言できない、または読みやすさにとって重要ではなく、変数の寿命が短いコンテキストで使用することをお勧めします。たとえば、イテレータタイプは通常長いため重要ではないため、auto
は機能します。
for(auto i = container.begin(); i != container.end(); ++i);
auto
ここは読みやすさを害しません。
別の例はパーサールールタイプで、長く複雑な場合があります。比較する:
auto spaces = space & space & space;
と
r_and_t<r_and_t<r_char_t<char>&, r_char_t<char>&>, r_char_t<char>&> spaces =
space & space & space;
一方、型が既知で単純な場合は、明示的に述べればはるかに優れています。
int i = foo();
のではなく
auto i = foo();
C++ and Beyond 2012(Ask Us Anything)パネルには、 a Andrei Alexandrescu、Scott Meyers、Herb Sutterの間でauto
を使用する場合と使用しない場合について話し合う素晴らしい交流 。 4分間のディスカッションのために25:03分にスキップします。 3人のスピーカーはすべて、auto
を使用するnotの場合に留意すべき優れた点を提供します。
私は人々が自分の結論に達することを強くお勧めしますが、私の重要なポイントは、auto
をどこでも使用することでしたunless:
explicit
を自由に使用すると、後者への懸念を減らすことができ、前者が問題になる時間を最小限に抑えることができます。
ハーブが言ったことを言い換えると、「X、Y、Zをしていないなら、auto
を使用します。X、Y、Zが何であるかを学び、他のどこでもauto
を使用します。」
auto
は、EigenやOpenCVなどの線形代数ライブラリで頻繁に使用される式テンプレートと組み合わせると非常に危険です。
auto A = Matrix(...);
auto B = Matrix(...);
auto C = A * B; // C is not a matrix. It is a matrix EXPRESSION.
cout << C; // The expression is evaluated and gives the expected result.
... // <code modifying A or B>
cout << C; // The expression is evaluated AGAIN and gives a DIFFERENT result.
このタイプの間違いによって引き起こされるバグは、デバッグするのに大きな苦痛です。考えられる解決策の1つは、左から右への宣言スタイルにautoを使用することに強いなら、結果を期待される型に明示的にキャストすることです。
auto C = Matrix(A * B); // The expression is now evaluated immediately.
私はauto
制限なしで使用していますが、問題はありませんでした。 int
のような単純な型に使用することさえあります。これにより、c ++は私にとってより高いレベルの言語になり、pythonのようにc ++で変数を宣言できます。 pythonコードを書いた後、私は時々.
auto i = MyClass();
の代わりに
MyClass i;
これは、auto
キーワードの乱用だと言う場合の1つです。
多くの場合、オブジェクトの正確なタイプは気にせず、その機能性にもっと興味があり、関数名は一般に、それらが返すオブジェクトについて何かを言うので、auto
は傷つきません: auto s = mycollection.size()
、s
は整数の一種であると推測できますが、まれに正確な型を気にする場合は、関数プロトタイプをチェックしましょう(つまり、 int_type s = mycollection.size()
)のように、いつの日か役に立つ場合に備えて、コードが書かれているときのアプリオリではなく、情報が必要なときにチェックしてください。
受け入れられた答えからのこの例に関して:
for ( auto x = max_size; x > 0; --x )
私のコードでは、この場合でもauto
を使用します。x
を無署名にする場合は、make_unsigned
という名前のユーティリティ関数を使用します。
for ( auto x = make_unsigned(max_size); x > 0; --x )
免責事項:my useについて説明しているだけで、アドバイスする能力はありません!
C++プログラムのmajor問題の1つは、uninitializedを使用できることです。変数。これは、厄介な非決定論的なプログラムの動作につながります。現在のコンパイラーは、プログラムが使い果たした場合に適切な/メッセージの警告メッセージをスローすることに注意してください。
これを説明するために、以下のc ++プログラムを検討してください。
int main() {
int x;
int y = 0;
y += x;
}
最新のコンパイラ(GCC)を使用してこのプログラムをコンパイルすると、警告が表示されます。実際の複雑な量産コードを使用している場合、このような警告はあまりはっきりしないかもしれません。
main.cpp:関数 'int main()'内:
main.cpp:4:8:warning: 'x'はこの関数で初期化されずに使用されます[-Wuninitialized]
y + = x;
^
================================================== =====================================今、auto、コンパイルすると次のようになります:
int main() {
auto x;
auto y = 0;
y += x;
}
main.cpp:関数 'int main()'内:
main.cpp:2:10:error: 'auto x'の宣言には初期化子がありません
auto x; ^
autoでは、初期化されていない変数を使用することはできません。これは、auto。
この概念と他のすばらしい最新のC++の概念は、C++の専門家 Herb Shutter の CppCon14 トークで説明されています。
私が指摘した危険の1つは、参照に関するものです。例えば.
MyBigObject& ref_to_big_object= big_object;
auto another_ref = ref_to_big_object; // ?
問題は、この場合、another_refは実際には参照ではなく、MyBigObject&ではなくMyBigObjectであるということです。あなたはそれを実現せずに大きなオブジェクトをコピーすることになります。
メソッドから直接参照を取得している場合、それが実際に何であるかを考えないかもしれません。
auto another_ref = function_returning_ref_to_big_object();
「auto&」または「const auto&」が必要です
MyBigObject& ref_to_big_object= big_object;
auto& another_ref = ref_to_big_object;
const auto& yet_another_ref = function_returning_ref_to_big_object();
auto
キーワードはローカル変数にのみ使用でき、引数またはクラス/構造体メンバーには使用できません。だから、あなたが好きな場所でそれらを使用することは安全で実行可能です。よく使います。型はコンパイル時に推測され、デバッガはデバッグ中に型を表示し、sizeof
はそれを正しく報告し、decltype
は正しい型を与えます-害はありません。私はauto
を使いすぎとしてカウントしません。
型を推論するのに意味がある場合は、auto
を使用します。整数であることがわかっているもの、または文字列であることがわかっている場合は、int/std :: stringなどを使用してください。またはコードを難読化します。
とにかくそれは私の意見です。
TL; DR:一番下の経験則を参照してください。
受け入れられた答え は、次の経験則を示唆しています。
一目で型の書き方を言うのが難しいときはいつでも
auto
を使用しますが、式の右側の型は明らかです。
しかし、私はそれがあまりにも制限的であると言うでしょう。いつか私は型について気にしません。なぜなら、型を理解するのに時間をかけることを気にせずに文が十分に有益であるからです。それはどういう意味ですか?いくつかの答えに現れた例を考えてみましょう:
auto x = f();
これがauto
の誤用の例になっているのはなぜですか? f()
の戻り値のタイプを知らないのですか?まあ、それを知っていれば本当に役立つかもしれませんが、それは私の主な関心事ではありません。さらに問題なのは、x
とf()
がほとんど意味がないということです。私たちが持っていた場合:
auto nugget = mine_gold();
代わりに、関数の戻り値の型が明らかであるかどうかは通常気にしません。ステートメントを読んで、私は自分が何をしているかを知っており、戻り値のセマンティクスがその型も知る必要があると感じないように十分に知っています。
したがって、私の答えは次のとおりです。コンパイラが許可する場合は常にauto
を使用します。
そしてまた:
auto
を具象型に置き換える前に、意味のある名前(もちろん型名を含まない)を与えることをお勧めします。