char! = (char firmado), char! = (char sin firmar)
Pregunta
El siguiente código se compila, pero tiene un comportamiento diferente para el tipo char que para los tipos int.
En particular
cout << getIsTrue< isX<int8>::ikIsX >() << endl;
cout << getIsTrue< isX<uint8>::ikIsX >() << endl;
cout << getIsTrue< isX<char>::ikIsX >() << endl;
da como resultado 3 instancias de plantillas para tres tipos: int8, uint8 y char. ¿Qué da?
Lo mismo no es cierto para ints: int y uint32 que dan como resultado la misma creación de instancias de plantilla y firmaron int en otro.
La razón parece ser que C ++ ve char, char firmado y unsigned char como tres tipos diferentes. Mientras que int es lo mismo que un int con signo. ¿Es correcto o me falta algo?
#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;
}
Estoy usando g ++ 4.algo
Solución
Aquí está su respuesta del estándar:
3.9.1 Tipos fundamentales [basic.fundamental]
Losobjetos declarados como caracteres (
char
) serán lo suficientemente grandes como para almacenar cualquier miembro del conjunto de caracteres básico de la implementación. Si un carácter de este conjunto se almacena en un objeto de carácter, el valor integral de ese objeto de carácter es igual al valor de la forma literal de un solo carácter de ese carácter. Está definido por la implementación si un objetochar
puede contener valores negativos. Los caracteres se pueden declarar explícitamente comounsigned
ofirmado
. Charlallana
,char firmada
ychar firmada
son tres tipos distintos. Achar
, unfirmado char
y ununsigned char
ocupan la misma cantidad de almacenamiento y tienen los mismos requisitos de alineación ( basic.types ); es decir, tienen la misma representación de objeto. Para los tipos de caracteres, todos los bits de la representación del objeto participan en la representación del valor. Para los tipos de caracteres sin signo, todos los patrones de bits posibles de la representación del valor representan números. Estos requisitos no son válidos para otros tipos. En cualquier particular implementación, un simple objetochar
puede tomar los mismos valores que unchar firmado
o ununsigned char
; cuál está definido por la implementación.
Otros consejos
Para preguntas como esta, me gusta consultar el documento de Fundamentos para C, que a menudo también proporciona respuestas a los misterios de C ++, que a veces surgen para mí cuando leo el Estándar. Tiene esto que decir al respecto:
Se especifican tres tipos de caracteres: con signo, sin formato y sin signo. Un carácter simple puede representarse como firmado o no, dependiendo de la implementación, como en la práctica anterior. El tipo de caracteres con signo se introdujo para poner a disposición un tipo de entero con signo de un byte en aquellos sistemas que implementan caracteres simples como sin signo. Por razones de simetría, la palabra clave con signo se permite como parte del nombre de tipo de otros tipos integrales.
Mientras que la mayoría de los tipos integrales como short
y int
están predeterminados para ser firmado
, char
no tiene un valor predeterminado señalización en C ++.
Es un error común con el que se encuentran los programadores de C ++ cuando usan char
como un tipo entero de 8 bits.
es correcto, char
, unsigned char
y igned char
son tipos separados. Probablemente hubiera sido bueno si char
fuera solo un sinónimo de igned char
o unsigned char
dependiendo de la implementación de su compilador, pero el estándar dice son tipos separados.