[解決済み] C++におけるlong long intとlong intとint64_tの比較
質問
私は C++ の型特性を使用しているときにいくつかの奇妙な動作を経験し、私の問題をこの風変わりで小さな問題に絞り込みました。
このようなプログラムを持っているとします。
#include <iostream>
#include <cstdint>
template <typename T>
bool is_int64() { return false; }
template <>
bool is_int64<int64_t>() { return true; }
int main()
{
std::cout << "int:\t" << is_int64<int>() << std::endl;
std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
std::cout << "long int:\t" << is_int64<long int>() << std::endl;
std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;
return 0;
}
GCCによる32ビットコンパイル(および32ビットと64ビットのMSVCによるコンパイル)のいずれにおいても、プログラムの出力は次のようになります。
int: 0
int64_t: 1
long int: 0
long long int: 1
しかし、64ビットGCCコンパイルの結果のプログラムは出力されます。
int: 0
int64_t: 1
long int: 1
long long int: 0
これは不思議なことで、なぜなら
long long int
は符号付き 64 ビット整数であり、どこからどう見ても
long int
と
int64_t
の型があるので、論理的には
int64_t
,
long int
と
long long int
は等価な型であり、これらの型を使用したときに生成されるアセンブリは同一である。 これらの型を使用したときに生成されるアセンブリは同じです。
stdint.h
を見れば、その理由がわかります。
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
64ビットコンパイルでは
int64_t
は
long int
ではなく
long long int
(当然)です。
この状況を解決するのはとても簡単です。
#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif
しかし、これは恐ろしくハチャメチャで、うまくスケールしない(実体のある機能。
uint64_t
など)。
そこで質問です。
コンパイラに
long long int
はまた
int64_t
と同じように
long int
は?
私の最初の考えは、C/C++ の型定義が機能する方法によって、これは不可能であるということです。 基本的なデータ型の型同等性をコンパイラーに指定する方法はなく、それはコンパイラーの仕事であるため (そして、それを許可すると多くのものが壊れる可能性がある)、また
typedef
は一方向にしか進みません。
また、私はここで答えを得ることにあまり関心がありません。これは超ド級のエッジケースであり、例が恐ろしく工夫されていないときには誰も気にしないと思われるからです(これはコミュニティWikiであるべきということでしょうか)。
追加 : のような簡単な例ではなく、部分的なテンプレート特化を使っているのが理由です。
void go(int64_t) { }
int main()
{
long long int x = 2;
go(x);
return 0;
}
は、この例がまだコンパイル可能であることを示しています。
long long int
は暗黙のうちに
int64_t
.
追加 : これまでの唯一の回答は、私が型が 64 ビットであるかどうかを知りたいと仮定しています。 私は、私がそのことを気にしていると考えるように人々を誤解させたくありませんでしたし、おそらく、この問題が顕在化する場所のより多くの例を提供するべきだったのです。
template <typename T>
struct some_type_trait : boost::false_type { };
template <>
struct some_type_trait<int64_t> : boost::true_type { };
この例では
some_type_trait<long int>
は
boost::true_type
が、しかし
some_type_trait<long long int>
にはなりません。 これはC++の型の考え方では理にかなっていますが、望ましいことではありません。
他の例としては、以下のような修飾子を使うことです。
same_type
(のような修飾子を使用することです(C++0x Conceptsではかなり一般的に使用されています)。
template <typename T>
void same_type(T, T) { }
void foo()
{
long int x;
long long int y;
same_type(x, y);
}
この例は、C++が型が異なると(正しく)認識するため、コンパイルに失敗します。 g++は、次のようなエラーでコンパイルに失敗します。
same_type(long int&, long long int&)
.
私が理解していることを強調したいのは なぜ
を理解していることを強調したいのですが、私はあちこちでコードを繰り返すことを強制されない回避策を探しています。どのように解決するのですか?
64bitにしなくても、このようなことはあります。考察
int32_t
を一般的な 32 ビットプラットフォームで考えてみましょう。それは
typedef
として編集されるかもしれません。
int
として、または
long
としても使えますが、明らかに一度にどちらか一方しか使えません。
int
と
long
はもちろん異なる型です。
とする回避策がないことは容易に理解できます。
int == int32_t == long
を 32 ビット システム上で実行する回避策がないことは容易に理解できるでしょう。同じ理由で、32 ビットシステム上で
long == int64_t == long long
を 64 ビット システム上で作る方法はありません。
もしできたとしたら、その結果は
foo(int)
,
foo(long)
と
foo(long long)
- というように、同じオーバーロードに対して2つの定義を持ってしまうのです。
正しい解決策は、テンプレートコードは通常、正確な型に依存するべきではなく、その型のプロパティに依存することです。全体の
same_type
のロジックは、特定のケースではまだOKかもしれません。
long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);
すなわち、オーバーロードの
foo(int64_t)
が定義されていない場合、それが
まさに
と同じ
foo(long)
.
[編集] C++11で、標準的な書き方ができるようになりました。
long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);
[編集] またはC++20
long foo(long x);
int64_t foo(int64_t) requires (!std::is_same_v<int64_t, long>);
関連
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み] C++でintをstringに変換する最も簡単な方法
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] C++テンプレート関数定義の.CPPファイルへの格納
-
[解決済み】どのような時にどのようなポインタを使えばいいのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む