重複の可能性:
C ++0xautoキーワードでは多すぎます
私たちは(コミュニティとして)自動車が悪用されている時期やかどうかを判断するのに十分な経験を持っていますか?
私が本当に探しているのは、に関するベストプラクティスガイドです。
- 自動を使用する場合
- 避けるべきとき
80%のケースですぐに従うことができる簡単な経験則。
文脈として、この質問はここでの私の応答によって引き起こされます
重複の可能性:
C ++0xautoキーワードでは多すぎます
私たちは(コミュニティとして)自動車が悪用されている時期やかどうかを判断するのに十分な経験を持っていますか?
私が本当に探しているのは、に関するベストプラクティスガイドです。
80%のケースですぐに従うことができる簡単な経験則。
文脈として、この質問はここでの私の応答によって引き起こされます
I think when the type is very well-known amongst the co-programmers who work (or would work) in your project, then auto
can be used, such as in the following code:
//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
//..
}
Or, more generally,
//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
//..
}
But when the type is not very well-known and infrequently used , then I think auto
seems to reduce readability, such as here:
//bad : auto decreases readability here
auto obj = ProcessData(someVariables);
While in the former case, the usage of auto
seems very good and doesn't reduce readability, and therefore, can be used extensively, but in the latter case, it reduces readabilty and hence shouldn't be used.
Another place where auto
can be used is when you use new
1 or make_*
functions , such as here:
//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);
//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);
Here it is very good, as it reduces the use of keyboard, without reducing the readability, as anyone can know the type of objects being created, just by looking at the code.
1. Avoid using new
and raw-pointers though.
Sometime, the type is so irrelevant that the knowledge of the type is not even needed, such as in expression template; in fact, practically it is impossible to write the type (correctly), in such cases auto
is a relief for programmers. I've written expression template library which can be used as:
foam::composition::expression<int> x;
auto s = x * x; //square
auto c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
Output:
0, 0
1, 1
4, 8
9, 27
16, 64
Now compare the above code with the following equivalent code which doesn't use auto
:
foam::composition::expression<int> x;
//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube
for(int i = 0; i < 5 ; i++ )
std::cout << s(i) << ", " << c(i) << std::endl;
As you can see, in such cases auto
makes your life exponentially easier. The expressions used above are very simple; think about the type of some more complex expressions:
auto a = x * x - 4 * x + 4;
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );
The type of such expressions would be even more huge and ugly, but thanks to auto
, we now can let the compiler infer the type of the expressions.
So the bottomline is: the keyword auto
might increase or decrease clarity and readability of your code, depending on the context. If the context makes it clear what type it is, or at least how it should be used (in case of standard container iterator) or the knowledge of the actual type is not even needed (such as in expression templates), then auto
should be used, and if the context doesn't make it clear and isn't very common (such as the second case above), then it should better be avoided.
簡単。タイプが何であるかを気にしない場合に使用します。例えば
for (auto i : some_container) {
...
ここで気にするi
のは、コンテナに入っているものだけです。
typedef に少し似ています。
typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
h
ここでは、 andw
が float であるか double であるかは気にしません。ただ、 height と weight を表現するのに適した型であることに注意してください。
または検討する
for (auto i = some_container .begin (); ...
ここで私が気にかけているのは、それが適切なイテレータであり、 をサポートしoperator++()
ていることだけです。この点では、ダック タイピングのようなものです。
また、ラムダの型は綴ることができないので、auto f = []...
良いスタイルです。代替手段はにキャストすることstd::function
ですが、それにはオーバーヘッドが伴います。
の「悪用」としか思えませんauto
。私が想像できる最も近いのは、重要な型への明示的な変換を自分自身から奪うことです-しかし、あなたはそれを使用せずauto
、目的の型のオブジェクトを構築します。
副作用を発生させずにコードの冗長性をいくらか取り除くことができれば、そうするのは良いことです。
var
C#の場合と同じルールを適用します:自由に使用してください。可読性が向上します。変数の型が実際に明示的に述べられるほど重要でない限り、その場合はこれを行う必要があります(当然)。
それでも、(特に静的に型付けされた言語では) コンパイラは、私たちよりも型の追跡に優れていると私は主張しています。ほとんどの場合、正確な型はそれほど重要ではありません (そうでなければ、インターフェイスは実際には機能しません)。どの操作が許可されているかを認識することがより重要です。コンテキストがそれを教えてくれるはずです。
さらに、初期化で不要な暗黙の変換を防ぐことにより、auto
実際にバグを防ぐことができます。一般に、型がなく、暗黙的な変換が存在する場合、ステートメントFoo x = y;
は暗黙的な変換を実行します。これが、そもそも暗黙の変換を避ける理由です。残念ながら、C++ にはすでにそれらが多すぎます。y
Foo
書くことで、原則としてauto x = y;
この問題を防ぐことができます。
一方、整数内の特定のバイト数を想定して計算を実行する場合、変数の明示的な型を知っていなければならず、明確に述べる必要があることは明らかです。
すべてのケースが明確であるとは限りませんが、ほとんどのケースがそうであると私は主張します。
C# コンパイラ チームの主任開発者であるEric Lippertは、var
.
あなたの最初の質問に対する答えはノーだと思います。いつ使用または避けるべきかについていくつかのガイドラインをまとめるのに十分な知識がありますauto
が、まだかなりの数のケースが残っています.
ほとんど使用しなければならない明らかなケースは、(たとえば) 2 つのジェネリック パラメーターに対する何らかの操作の結果を保持する適切な型が必要な場合のテンプレートです。このような場合、悪用の唯一の可能性はそれ自体の悪用ではありませんがauto
、実行している一般的な操作の種類 (または作成しているテンプレートの種類など) があなたがするものであるかどうかです。避けたほうがいい。
また、明らかに避ける必要がある状況が少なくともいくつかありますauto
。目前の仕事の一部を行うためにproxy->targetからの変換に依存しているプロキシタイプのようなものを使用している場合auto
、ソースと同じタイプのターゲットを作成(しようと)するので、変換起こりません。場合によっては、変換が遅延するだけかもしれませんが、まったく機能しない場合もあります (たとえば、プロキシ タイプが代入をサポートしていない場合がよくあります)。
もう 1 つの例は、外部インターフェイスのようなもののために、特定の変数が特定の型を持つことを保証する必要がある場合です。たとえば、ネットワーク マスクを IP (v4) アドレスに適用することを検討してください。議論のために、アドレスの個々のオクテット (たとえば、それぞれを として表すunsigned char
) を扱っていると仮定すると、最終的には のような結果になりoctets[0] & mask[0]
ます。C の型昇格規則のおかげで、両方のオペランドがunsigned char
s であっても、通常、結果は になりますint
。結果は、 (通常は 4 オクテット)ではなく、ただし (つまり、1 オクテット) である必要があります。そのため、この状況では、ほぼ間違いなく不適切です。unsigned char
int
auto
ただし、それでも判断が必要な場合がたくさんあります。これらのケースに対する私自身の傾向auto
は、デフォルトとして扱い、上記で引用した後者のケースに少なくとも少し似ているケースでのみ明示的なタイプを使用することです-正しい操作に特定のタイプが必要ない場合でもたとえそれが暗黙の変換を伴うかもしれないとしても、私は本当に特定の型が欲しい.
私の推測では (これは推測にすぎませんが)、時間の経過とともに、おそらくさらにその方向に傾くでしょう。コンパイラが型を選択することに慣れるにつれて、型を指定する必要があると現在考えているかなりの数のケースが、実際には必要なく、コードがうまくいくことがわかります。
私は、私たちの多く (そして、年をとったり経験を積んだりするほど、おそらくそれについては悪くなるでしょう) が、最終的にはパフォーマンスについての何らかの感情にさかのぼる理由で明示的な型を使用し、私たちの選択がパフォーマンスを向上させると信じているのではないかと思います。 . 場合によっては、私たちが正しいことさえあるかもしれませんが、多くの経験を持つ私たちのほとんどが気付いているように、私たちの推測はしばしば間違っています (特に暗黙の仮定に基づいている場合)。時間の経過とともに。
完全な型推論で言語を使用しました。技術的に可能なすべての場所に配置しない理由はありませんauto
*。実際、私はすでに を書いているかもしれauto i = 0;
ませint
んauto
。一番下の理由は、私はマニフェストの型付けを気にしないからです。
*: たとえば、auto int[] = { 0, 1, 2, 3 }
動作しません。
長いテンプレートやラムダ関数型などの長い反復型でのみ使用してください。物事を明確にすることができれば、それを避けるようにしてください。