Подтвердить что ты не робот

Char!= (подпись char), char!= (без знака char)

Приведенный ниже код компилируется, но имеет различное поведение для типа char, чем для типов int.

В частности,

   cout << getIsTrue< isX<int8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<uint8>::ikIsX  >() << endl;
   cout << getIsTrue< isX<char>::ikIsX  >() << endl;

приводит к 3 экземплярам шаблонов для трех типов: int8, uint8 и char. Что дает?

То же самое не относится к ints: int и uint32, которые приводят к тому же экземпляру шаблона, и подписали int other.

Причина в том, что С++ видит char, подписанный char и unsigned char как три разных типа. Если int совпадает с подписанным int. Это правильно или я что-то упускаю?

#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

4b9b3361

Ответ 1

Вот ваш ответ со стандартом:

3.9.1 Основные типы [basic.fundamental]

1 Объекты, объявленные как символы char), должны быть достаточно большими, чтобы хранить любой элемент базового набора символов реализации. Если символ из этого набора сохраняется в символьном объекте, целочисленное значение этого символьного объекта равно значению односимвольной литеральной формы этого символа. Определяется реализация, может ли объект char содержать отрицательные значения. Символы могут быть явно объявлены без знака или подписаны. Обычная char, подписанная char и unsigned char - три разных типа. A char, подписанный char и неподписанный char занимают одинаковое количество хранения и имеют одинаковые требования к выравниванию (basic.types); то есть они имеют одно и то же представление объекта. Для типов символов в представлении значения участвуют все биты представления объекта. Для неподписанных типов символов все возможные битовые шаблоны представления значений представляют числа. Эти требования не подходят для других типов. В любом конкретном реализация, простой объект char может принимать те же значения, что и подписанный char или unsigned char; какой из них определяется реализацией.

Ответ 2

Для таких вопросов, как это, я хотел бы изучить документ Rationale для C, который часто дает ответы на тайны С++, которые иногда возникают у меня при чтении стандарта. Об этом он говорит:

Указаны три типа char: signed, plain и unsigned. Простой char может быть представлен как подписанный, так и неподписанный, в зависимости от реализации, как в предыдущей практике. Был введен тип подписанный char, чтобы сделать доступным однобайтовый целочисленный тип со знаком в тех системах, которые реализуют plain char как unsigned. По соображениям симметрии ключевое слово, подписанное, разрешено как часть имени типа других интегральных типов.

Обоснование для C

Ответ 3

В то время как большинство интегральных типов, таких как short и int по умолчанию, являются signed, char не имеет знака по умолчанию в С++.

Это распространенная ошибка, с которой сталкиваются программисты на С++, когда они используют char как 8-битный целочисленный тип.

Ответ 4

которые правильны, char, unsigned char и signed char являются отдельными типами. Вероятно, было бы неплохо, если бы char был просто синонимом для signed char или unsigned char в зависимости от реализации ваших компиляторов, но стандарт говорит, что они являются отдельными типами.