web-dev-qa-db-ja.com

コンパイル時に短いものと長いものを自動的に区別するにはどうすればよいですか?

C++プログラムでauto変数を使用することに興奮しています。 autoで宣言された変数は、テンプレートルールを使用して変数の型を推測しますが、数値型に対してどのように機能するかについては混乱しています。私が持っていると仮定します:

auto foo = 12;

fooのタイプは、合理的にintまたはunsigned charになります。しかし、後のプログラムで数学を実行し、fooに40億の値を割り当てたとします。その時点で、foounsigned intまたはlong型にしたいでしょう。

コンパイラは、プログラムの後半で割り当てられる値をどのように予測できますか?

22
David Lobron

コンパイラは、存在する情報が整数リテラル12である情報を処理します。したがって、fooint型であると推定されます。何も予想していません。適切な 整数リテラル サフィックスを使用できます。

auto foo = 12ul;

foounsigned longとして推定するように強制します。変数をint型に定義することはできません。その後、以前使用した型に収まらない別の値を割り当てたという理由だけで、コンパイラが何らかの方法で変数を別の型に変更することを期待します。これを行うと、単純に整数オーバーフローが発生し、未定義の動作になります。

このテーマの詳細については、 自動指定子 および 自動型推定 リファレンスを参照してください。

50
Ron

"fooの型は合理的にintまたはunsigned charである可能性があります"

いいえ、できません。 C++のすべての式には型があり、言語で明確に定義されています。あなたの場合、式は整数リテラルであるため、型はリテラルに対応します。具体的にどのタイプであるかは、 rules で定義されます:

リテラルのタイプ

整数リテラルのタイプは、使用される数値ベースと整数サフィックスに依存するタイプのリストから、値が収まる最初のタイプです。

接尾辞なし-int、long int、long long int(C++ 11以降)

"コンパイラは、プログラムの後半で割り当てられる値をどのように予測できますか?"

できない。型は変数を宣言するときに決定され、後で変更することはできません。

23
Slava

Fooの型は合理的にintまたはunsigned charです

それはcould be多くのものですが、実際にはis一つだけです。

整数リテラル12のタイプはintです。

期間。

しかし、私のプログラムの後半で、いくつかの計算を行い、fooに40億の値を割り当てたとします。その時点で、fooにunsigned int型またはおそらくlong型を持たせたいと思います。コンパイラは、プログラムの後半で割り当てられる値をどのように予測できますか?

彼らはできませんし、しません。 fooのタイプは変更されません。 fooにはauto型がありません(そのようなものはありません)。タイプはintです。以降のプログラムは、あなたがint foo = 12;。推論/自動化はそこで終わります。

その時点で、foounsigned intまたはlong型を持たせたいと思います。

それは言語の仕組みではありません。実行時に変数の型を変更することはできません。変数をauto foo = 12;として定義および初期化する場合、将来の割り当てに関係なく、int foo = 12;のタイプはであるため、exactly12と同じことint

コンパイラは、プログラムの後半で割り当てられる値をどのように予測できますか?

彼らはする必要はありません。後で割り当てられる値は、変数の型に変換されます。値がそのタイプの範囲外である場合、正確なルールは処理しているタイプによって異なります。

5
user743382

私のアドバイスは、これはautoを使用するのに適した場所ではないということです。どの要素が必要なタイプを決定するかを知っており、それらを直接のコンテキストから推定することはできません。 (ただし、変数を単一の静的割り当てとして記述できる場合、それは起こりません。)

変数が少なくとも40億の値を保持できる必要があることがわかっている場合は、unsigned longまたはlong long int。または、これらのタイプの幅の不幸な選択(レガシーコードをサポートするためにlongが32ビット幅であるがネイティブのWordサイズが64ビットであるプラットフォームなど)に対して防御的にコーディングしたい場合は、それを宣言しますuint_fast32_tまたはint_fast64_t。または、最速ではなく最小のものが必要な場合は、uint_least32_t。 (場合によっては、最速のコードがキャッシュにほとんどの値を保持するものです!)

本当に欲しいのが、40億の値を保持できる最速の署名付きまたは署名なしのタイプである場合、その意味を言ってください!

4
Davislor

個人的には、これらの直接定数にはautoを使用しませんが、値は別のメソッド呼び出しから取得されるか、別の変数から割り当てられます。

別の変数の型と一致するように変数を定義する方法が必要な場合、その変数と相互運用できますが、定数値を割り当てたい場合は、decltypeを使用してそのサイズに互換性があることを確認します。

decltype(otherVar) myVar = 1234;
myVar += otherVar;  // will work just as well as otherVar += myVar

いずれの場合でも、型はリテラル定数で指定され、装飾されていない12はintを定義します。

ただし、定数をデコレートできますでU、符号なしにするか、Lで長くするか、LLでさらに長くします。残念ながら、それをshortまたはcharに強制することに相当するものはありません!

1
Gem Taylor