2012-09-27 21 views
7

En C# Puedo escribir algo como esto:¿Cómo obtener el valor por defecto de cualquier tipo

class AnyThing<T> 
    { 
     static public T Default = default(T); 
    } 

    static void Main() 
    { 
     int i = AnyThing<int>.Default; 
     Console.WriteLine (i==0); 
     string s = AnyThing<string>.Default; 
     Console.WriteLine (s == null); 

    } 

tengo la intención de escribir un diccionario como clase de plantilla en C++, me gustaría que el dict para devolver el valor predeterminado valor (cero fuera) del tipo de TVal genérico si no se encuentra la clave dada. En C#, el constructo por defecto (T) viene a rescatar, mientras que en C++ no estoy seguro de cuál es la forma apropiada de hacer lo mismo.

He intentado T obj = {} y T* obj = {} con gcc4.7, funciona bien. Simplemente no estoy seguro si es la sintaxis definida por la especificación del lenguaje, si este tipo de código será portable compiladores cruzados y plataformas. ¡Por favor ayúdame con mi doudt! ¡Gracias por adelantado!

PS:

~~~~~~~~~~

Para asegurarse de que la plantilla de obtener el valor por defecto (cero fuera) valor de cualquier tipo, incluso de aquellos que no tienen exigible Héctor defecto, que empleó siguiente mecanismo (inspirado por la respuesta de avakar):

template<class T> 
struct AnyThing 
{ 
    static const T& Default ; 
private: 
    static const char temp[sizeof(T)]; 
}; 

template<class T> const char AnyThing<T>::temp[] = {}; 
template<class T> const T& AnyThing<T>::Default = *(T*)temp; 

struct st 
{ 
    double data; 
    st()=delete; 
}; 

int main() 
{ 
    cout << (int)AnyThing<char*>::Default<<endl; //0 
    cout << AnyThing<int>::Default<<endl;  //0 
    cout <<AnyThing<st>::Default.data<<endl;  //0 
} 

se ve feo, pero no debe causar ningún problema, después de todo un objeto llevado a cero es sólo un trozo de memoria en blanco. ¿Me equivoco?

+0

http://stackoverflow.com/questions/1962600/what-is-the-c-cli-equivalent-to-cs-defaultt – Khurshid

+0

No estoy del todo seguro de que esto resuelva tu problema, pero creo que [Boo st.Value Initialized] (http://www.boost.org/doc/libs/release/libs/utility/value_init.htm) trata de resolver este problema. –

Respuesta

19

En C++ no hay nada como default palabra clave en C#. Dado que la inicialización por defecto del constructor del valor del tipo de clase fallará, si el constructor predeterminado es private. En C#, si el constructor predeterminado es privado, el valor del tipo de clase se inicializará en null, ya que class-type es reference-type.

La inicialización por {} se define por especificación de idioma. Es C++ 11. En C++ 03 se debe utilizar

T obj = T(); 

Como se ha señalado por bames53 en el comentario, cuando se desea inicializar T* se debe utilizar

antes de C++ 11.

T* obj = 0; 

o

T* obj = NULL; 

en C++ 11.

T* obj = {}; 

o

T* obj = nullptr; 
+0

¿Esto también funciona para los tipos de puntero? – Need4Steed

+4

'double * obj = double()' no funciona. –

+1

@ Need4Steed, funciona para tipos de puntero si por "funciona" quiere decir que el valor predeterminado del puntero es nulo. "Works" es una manera breve de decir "cumple mis expectativas"; al igual que la frase más larga, no revela cuál es el resultado esperado en realidad. Pero al menos es corto, – rici

3

Tomado literalmente de "The C++ Programming Language, tercera edición por Bjarne Stroustrup":

COMENZAR CITA

4.9.5 Inicialización [dcl.init]

Si se especifica un inicializador para un objeto, ese inicializador determina la valor inicial de un objeto. Si no se especifica ningún inicializador, se inicializa a 0 del tipo apropiado un espacio de nombre global (§4.9.4), (8.2) u objeto estático local (§7.1.2, §10.2.4) (colectivamente llamados objetos estáticos) .Por ejemplo:

int a; // means int a=0; 
double d; // meands d=0; 

Las variables locales (a veces llamados objetos automáticos) y objetos creados en la tienda libre (a veces llamado objetos dinámicos u objetos del montón) no se inicializan por defecto. Por ejemplo:

void f() 
{ 
    int x; // x does not have a well-defined value 
    // . . . 
} 

Los miembros de las matrices y las estructuras se inicializan por defecto o no dependiendo de si la matriz o la estructura es estática. Los tipos definidos por el usuario pueden tener una inicialización predeterminada definida (§10.4.2).

Los objetos más complicados requieren más de un valor como inicializador. Esto se maneja mediante listas de inicializadores delimitadas por {y} para la inicialización de matrices en C (§5.2.1) y estructuras (§5.7).

Para los tipos definidos por el usuario con constructores, se utilizan listas de argumentos de estilo de función (§2.5.2, §10.2.3). Tenga en cuenta que un par vacío de paréntesis() en una declaración siempre significa '' función '' (§7.1). Por ejemplo:

int a[] = {1,2}; // array initializer 
Point z(1,2);  // function-style initializer (initialization by constructor) 
int f();   // function declaration 

Fin de la cita

Por lo tanto, se puede obtener el valor por defecto de cualquier tipo forman un objeto estático de ese tipo:

static T defaultT; // `defaultT' has de default value of type T 
+0

Pero descubrí que la solución 'T()' deja de funcionar si eliminé el defecto de T, o lo declare como privado, pero en C# 'predeterminado (T)' funciona de todos modos, por lo que no funciona para CUALQUIER tipo! Qué retroceso1 – Need4Steed

+2

@ Need4Steed Sí, ya que C# tiene tipos de referencia y tipos de valores. Todos los tipos de clase son tipos de referencia y pueden inicializarse mediante nulo, C++ no tiene tal cosa. – ForEveR

+2

La mejor respuesta, directamente del inventor de C++. ¿Por qué diablos esta respuesta tiene tan pocos votos? ¡Para vergüenza! Gracias, Roy. –

3

para siempre respuesta no funcionará si T doesn No tengo un constructor de copia. En C++ 03, no hay forma de inicializar a cero una variable genérica y elegante. Todo lo que queda es el siguiente truco.

T temp[1] = {}; 
T & obj = temp[0]; 

Aquí, temp[0] se inicializa a cero y luego obligado a obj. No se necesitan constructores de copia.

1

Cree su propia palabra clave por defecto:

class default_t 
{ 
public: 
    template<typename T> 
    operator T() const { return T(); } 
}; 

default_t const default = default_t(); 

usarlo como:

int myInt = default; 
vector<string> myVector = default; 
shared_ptr<string> myPtr = default; 

o con una ligera variación semántica:

default_t const empty = default_t(); 

vector<Persons> fetchPersons() 
{ 
    if (Database::isConnected()) 
    { 
    return Database::fetchPersons(); 
    } 

    return empty; 
} 
Cuestiones relacionadas