2010-02-04 18 views
13

Quiero declarar mis propios tipos numéricos, exactamente como unsigned int, pero no quiero que los tipos se conviertan implícitamente. Intenté esto primero: typedef unsigned int firstID; typedef unsigned int secondID;Declarar tipos sin conversión implícita en C++

pero esto no es bueno ya que los dos tipos son solo sinónimos de unsigned int, por lo que se pueden intercambiar libremente.

me gustaría que esto causará un error:

firstID fid = 0; 
secondID sid = fid; // no implicit conversion error 

pero esto a estar bien:

firstID fid = 0; 
secondID sid = static_cast<secondID>(fid); // no error 

Mi razón es para que los argumentos de funciones están fuertemente tipado, por ejemplo:

void f(firstID, secondID); // instead of void f(unsigned int, unsigned int) 

¿Cuál es el mecanismo que estoy buscando?

Gracias

de Si

+1

A menos que los tipos sean clases o estructuras reales, no hay forma de hacerlo. –

+0

¿No fue esto lo que se le preguntó? http://stackoverflow.com/questions/376452/enforce-strong-type-checking-in-c-type-strictness-for-typedefs – Manuel

Respuesta

7

Tal forma BOOST_STRONG_TYPEDEF boost/strong_typedef.hpp ayudaría.

+0

Tiene sentido que Boost tenga esto. No es ciencia espacial, pero es mucho trabajo conseguir todos los operadores, y está pidiendo a gritos una plantilla. –

+0

Me encanta impulsar. Siempre tiene una respuesta – sipi

2

Tienes que escribir sus propias clases para ellos, reimplementar todos los operadores que necesita.

+0

¡Ay, esperaba que fuera sencillo! Es una pena que no puedas heredar de una int sin firmar! – sipi

+2

Sin embargo, puede escribir la clase como una plantilla, por lo que funcionará con todos los tipos primitivos al menos. – OregonGhost

1

Ahhh, un compañero de viaje de Ada que veo.

La única manera real de hacerlo en C++ es declarar las clases. Algo así como:

class first_100 { 
public: 
    explicit first_100(int source) { 
     if (source < 1 || source > 100) { 
      throw range_error; 
     } 
     value = source; 
    }; 
    // (redefine *all* the int operators here) 
private: 
    int value; 
}; 

Usted querrá asegurarse para definir su constructor int explicit de manera que C++ no va a utilizarlo para convertir implícitamente entre sus tipos. De esa manera, esto no funcionará:

first_100 centum = first_100(55); 
int i = centum; 

pero algo como esto podría (suponiendo que lo define):

int i = centum.to_int(); 
1
struct FirstID { int id; }; 
3

Como se señaló: typedef está mal nombrado (debe ser typealias (D ha añadido explícitamente typealias (última vez que se veía))

Así que la única manera de hacer esto es crear dos únicos clases
No voy a decir que no puedes escribir una especialización de static_cast <> para hacer lo que quieras, pero creo (y no lo he pensado mucho aún) hacerlo sería una mala idea (incluso si es legal), creo que un mejor enfoque es hacer que cada constructor de clase use unsigned int que sean explícitos (para que no haya conversión automática).

struct FID 
{ 
    explicit FID(unsigned int v): value(v) {} 
    operator unsigned int() {return value;} 
    unsigned int value; 
}; 

class SID {/* Stuff */}; 

FID fid(1U); 
SID sid(2U); 

doSomthingWithTwoSID(sid,SID(static_cast<unsigned int>(fid)); 

Convertir el constructor en explícito significa que no hay conversión automática entre los tipos.
Al agregar el operador de conversión integrado a unsigned int significa que se puede usar en cualquier lugar donde se espere int.

Cuestiones relacionadas