以下のコードはコンパイルされますが、char型とint型では動作が異なります。
特に
cout << getIsTrue< isX<int8>::ikIsX >() << endl;
cout << getIsTrue< isX<uint8>::ikIsX >() << endl;
cout << getIsTrue< isX<char>::ikIsX >() << endl;
結果として、int8、uint8、charの3つのタイプのテンプレートが3つインスタンス化されます。何が得られますか?
同じことはintには当てはまりません:同じテンプレートのインスタンス化をもたらすintとuint32、および別の署名されたint。
その理由は、C++がchar、signed char、unsignedcharを3つの異なるタイプと見なしているためと思われます。一方、intはsignedintと同じです。これは正しいですか、それとも何かが足りませんか?
#include <iostream>
using namespace std;
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef signed int int32;
typedef unsigned int uint32;
typedef signed long long int64;
typedef unsigned long long uint64;
struct TrueType {};
struct FalseType {};
template <typename T>
struct isX
{
typedef typename T::ikIsX ikIsX;
};
// This int==int32 is ambiguous
//template <> struct isX<int > { typedef FalseType ikIsX; }; // Fails
template <> struct isX<int32 > { typedef FalseType ikIsX; };
template <> struct isX<uint32 > { typedef FalseType ikIsX; };
// Whay isn't this ambiguous? char==int8
template <> struct isX<char > { typedef FalseType ikIsX; };
template <> struct isX<int8 > { typedef FalseType ikIsX; };
template <> struct isX<uint8 > { typedef FalseType ikIsX; };
template <typename T> bool getIsTrue();
template <> bool getIsTrue<TrueType>() { return true; }
template <> bool getIsTrue<FalseType>() { return false; }
int main(int, char **t )
{
cout << sizeof(int8) << endl; // 1
cout << sizeof(uint8) << endl; // 1
cout << sizeof(char) << endl; // 1
cout << getIsTrue< isX<int8>::ikIsX >() << endl;
cout << getIsTrue< isX<uint8>::ikIsX >() << endl;
cout << getIsTrue< isX<char>::ikIsX >() << endl;
cout << getIsTrue< isX<int32>::ikIsX >() << endl;
cout << getIsTrue< isX<uint32>::ikIsX >() << endl;
cout << getIsTrue< isX<int>::ikIsX >() << endl;
}
私はg ++ 4.somethingを使用しています
これが標準からのあなたの答えです:
3.9.1基本タイプ[basic.fundamental]
文字(
char
)として宣言されたオブジェクトは、実装の基本文字セットのメンバーを格納するのに十分な大きさでなければなりません。このセットの文字が文字オブジェクトに格納されている場合、その文字オブジェクトの整数値は、その文字の単一文字リテラル形式の値に等しくなります。char
オブジェクトが負の値を保持できるかどうかは実装によって定義されます。文字は明示的にunsigned
またはsigned
として宣言できます。 プレーンchar
、signed char
、およびunsigned char
は、3つの異なるタイプです。char
、signed char
、およびunsigned char
は同じ量のストレージを占有し、同じ配置要件を持ちます(basic.types);つまり、それらは同じオブジェクト表現を持っています。文字タイプの場合、オブジェクト表現のすべてのビットが値表現に参加します。符号なし文字タイプの場合、値表現のすべての可能なビットパターンは数値を表します。これらの要件は、他のタイプには当てはまりません。特定の実装では、プレーンなchar
オブジェクトはsigned char
またはunsigned char
と同じ値を取ることができます。どちらが実装定義です。
このような質問については、Cの理論的根拠のドキュメントを調べたいと思います。このドキュメントには、C++の謎に対する回答も含まれていることが多く、標準を読んでいるときに時々発生します。それについて言うことはこれを持っています:
文字には、signed、plain、unsignedの3種類が指定されています。プレーン文字は、以前の慣例のように、実装に応じて、符号付きまたは符号なしのいずれかとして表すことができます。タイプsignedcharは、プレーンcharをunsignedとして実装するシステムで1バイトのsignedintegerタイプを使用できるようにするために導入されました。対称性の理由から、signedキーワードは、他の整数型の型名の一部として許可されています。
short
やint
のようなほとんどの整数型はデフォルトでsigned
ですが、char
にはC++のデフォルトのサイネージがありません。
C++プログラマーがchar
を8ビット整数型として使用するときに遭遇するのはよくある間違いです。
正解です。char
、unsigned char
、およびsigned char
は別々のタイプです。 char
がコンパイラの実装に応じてsigned char
またはunsigned char
の同義語であるとしたら、おそらく良かったと思いますが、標準では、これらは別々の型であるとされています。