Приведенный ниже код компилируется, но его поведение для типа 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 - к другому.
Причина, по-видимому, в том, что C++ видит char, signed 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. что-то
"int и uint32, которые приводят к тому же экземпляру шаблона, а подписанный int другой", это определенно должно быть наоборот, поскольку int подписан.





это правильно, char, unsigned char и signed char - это разные типы. Вероятно, было бы неплохо, если бы char был просто синонимом signed char или unsigned char, в зависимости от реализации вашего компилятора, но в стандарте говорится, что это разные типы.
Вот ваш ответ из стандарта:
3.9.1 Fundamental types [basic.fundamental]
Objects declared as characters (
char) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether acharobject can hold negative values. Characters can be explicitly declaredunsignedorsigned. Plainchar,signed char, andunsigned charare three distinct types. Achar, asigned char, and anunsigned charoccupy the same amount of storage and have the same alignment requirements (basic.types); that is, they have the same object representation. For character types, all bits of the object representation participate in the value representation. For unsigned character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types. In any particular implementation, a plaincharobject can take on either the same values as asigned charor anunsigned char; which one is implementation-defined.
В то время как большинство интегральных типов, таких как short и int, по умолчанию являются signed, char не имеет обозначений по умолчанию в C++.
Это не тип signed char и не unsigned char, поэтому реализации могут решить, подписан ли он.
Это распространенная ошибка, с которой сталкиваются программисты на C++, когда используют char как 8-битный целочисленный тип.
+1, потому что вы очень кратко объясняете различия в типах данных и подразумеваете, как их следует использовать в сравнении.
Историческая сноска: я слышал, что это произошло потому, что ранние версии C не указывали подписи char, поэтому разные компиляторы делали разные вещи, а затем стандарт сохранил это поведение, чтобы старый код продолжал работать с теми же компиляторами.
По таким вопросам, как этот, мне нравится заглядывать в документ Rationale для C, который также часто дает ответы на загадки C++, которые иногда возникают у меня при чтении Стандарта. Об этом говорится следующее:
Three types of char are specified: signed, plain, and unsigned. A plain char may be represented as either signed or unsigned, depending upon the implementation, as in prior practice. The type signed char was introduced to make available a one-byte signed integer type on those systems which implement plain char as unsigned. For reasons of symmetry, the keyword signed is allowed as part of the type name of other integral types.
Итак, зачем нам signed char? Просто для того, чтобы использовать его для представления однобайтового целого числа со знаком?
@Alcott я думаю, что char может быть подписан или может быть без знака, что определяется реализацией, но signed char всегда подписан, а unsigned char всегда без знака, если вы хотите быть уверенным / явным в типе
Вы также должны отметить, что нет никакой гарантии, что
int8_tбудетsigned char, аuint8_tбудетunsigned char. В частности, в Solarisint8_t- это простоchar, еслиcharподписан. Другими словами, ваш код там не скомпилируется.