Символ!=(подписанный символ), символ!=(без знака)

Код ниже компилируется, но имеет другое поведение для типа char, чем для типов int.

Особенно

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

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

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

Причина, по-видимому, в том, что C++ видит 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. что-то

4 ответа

Решение

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

3.9.1 Фундаментальные типы [basic.fundamental]

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

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

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

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

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

Обоснование C

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

Другие вопросы по тегам