Символ!=(подписанный символ), символ!=(без знака)
Код ниже компилируется, но имеет другое поведение для типа 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++, которые иногда возникают у меня при чтении Стандарта. Это говорит об этом:
Указаны три типа символов: подписанный, простой и неподписанный. Простой символ может быть представлен как подписанный или неподписанный, в зависимости от реализации, как в предыдущей практике. Тип подписанного символа был введен, чтобы сделать доступным однобайтовый целочисленный тип со знаком в тех системах, которые реализуют обычный символ как неподписанный. По соображениям симметрии ключевое слово подписывается как часть имени типа других целочисленных типов.
Правильно, char
, unsigned char
а также signed char
это отдельные типы. Это было бы неплохо, если бы char
был просто синонимом либо signed char
или же unsigned char
в зависимости от реализации ваших компиляторов, но стандарт говорит, что они являются отдельными типами.