2012-06-18 11 views
8

Estoy tratando de encontrar una solución para tener literales numéricos constantes dentro del método de clase de plantilla. Estoy haciendo algunas clases de plantillas matemáticas para usar con tipos flotantes o dobles. El problema es que los literales son diferentes según el tipo de datos (por ejemplo, "0.5f" para flotar y "0.5" para el doble). Hasta ahora, se me ocurren dos soluciones. Parte del código hipotética de primera:Especialización de funciones en clase de plantilla para literales float y dobles

template <typename T> 
class SomeClass 
{ 
    public: 
     T doSomething(T x); 
}; 

template <> 
float SomeClass<float>::doSomething(float x) 
{ 
    float y = 0.5f; 
    /* 
    * Do computations... 
    */ 
    return x; 
} 

template <> 
double SomeClass<double>::doSomething(double x) 
{ 
    double y = 0.5; 
    /* 
    * Do computations... 
    */ 
    return x; 
} 

El enfoque anterior fuerzas reescritura métodos integrales para cada tipo se utiliza con.

Otro enfoque:

template <typename T> 
class SomeClass 
{ 
    public: 
     T doSomething(T x); 

    private: 
     T getValue(); 
}; 

template <typename T> 
T SomeClass<T>::doSomething(T x) 
{ 
    T y = getValue(); 
    /* 
    * Do computations... 
    */ 
    return x; 
} 

template <> 
float SomeClass<float>::getValue() 
{ 
    return 0.5f; 
} 

template <> 
double SomeClass<double>::getValue() 
{ 
    return 0.5; 
} 

Ésta no exige a escribir mismos métodos múltiples veces para el tipo específico, pero requiere tener una gran cantidad getValue() métodos para cada "número mágico" que necesitan ser utilizado dentro del método.

¿Hay alguna otra forma "más elegante" de resolver esto?

+1

Si sólo está a literales, creo que se puede utilizar de fundición static_cast () – Mohammad

+0

que no he mencionado en mi pregunta, pero me gustaría evitar cualquier conversión, explícitas ni implícitas ni. – umebe

Respuesta

0

Simplemente no tiene que preocuparse por esto - use 0.5 y si el tipo es flotante, el compilador aún lo inicializará de manera óptima al mismo valor que si hubiera usado 0.5f.

Es un poco largo aliento, pero es posible que desee leer a través de los "otros mecanismos de apoyo polimorfismo" parte de mi respuesta aquí: Polymorphism in c++

Para un uso más general de la constante de flotación en toda la función - en particular en comparaciones y expresiones - vale la pena leer el enlace que bluemess menciona a continuación ...

+0

Supongamos que usaré el literal "0.5". ¿Eso no causaría que la conversión implícita (tiempo de ejecución?) Flote en algún punto? En el ejemplo que di, puede que no sea importante, pero en general preferiría evitar las conversiones. – umebe

+1

Sería una conversión en tiempo de compilación. –

+0

He encontrado que usar literal "0.5" para flotar en algunos casos dará lugar a conversiones múltiples que se explican aquí: [¿Deberíamos generalmente usar literales float para flotantes en lugar de los literales dobles más simples?] (Http://stackoverflow.com/a/7662804/1464168) – umebe

0

Suponiendo que es realmente necesario usar valores diferentes en las dos especializaciones (no es necesario para 0.5 y 0.5f, por ejemplo) sería mucho menos tipeando que hacer:

template <typename T> 
class SomeClass 
{ 
    public: 
    T doSomething(T x); 

    private: 
    static const T magic_number_1; 
}; 

template <typename T> 
T SomeClass<T>::doSomething(T x) 
{ 
    T y = magic_number_1; 
    /* 
    * Do computations... 
    */ 
    return x; 
} 

template <> 
const float SomeClass<float>::magic_number_1 = 0.5f; 

template <> 
const double SomeClass<double>::magic_number_1 = 0.5; 
+0

Correcto, esto parece ser mejor que separar los métodos getValue(). – umebe

1

Gracias a todos por sus respuestas y comentarios. Me permití hacer un resumen de lo que se ha dicho hasta ahora y agregar mis conclusiones.

Voy a implementar una plantilla de clase de matemáticas para crear una instancia para utilizar con tipo flotante o doble. Hay una necesidad de usar algunos literales numéricos internamente en la clase. Serán algunos literales y constantes numéricos comúnmente utilizados, como 0.0, 0.5, 1.0, pi, etc. Estoy buscando una solución para hacer que la creación de instancias de clase funcione en diferentes literales, dependiendo de su tipo.

Si usa o no float y literales dobles?

Habló un poco sobre el tema si se molesta o no en usar literales separados para flotación y doble. Esto podría ser causado por un pequeño ejemplo desafortunado que di en mi pregunta. En el ejemplo, el literal se convertirá al tipo correcto en el tiempo de compilación de todos modos, por lo que no se producirá ningún daño. Pero, en general, habrá casos en los que las necesidades literales a ser utilizados en la expresión, por ejemplo:

float foo(float x) 
{ 
    return x * 3.14; 
} 

Esto obligará compilador para convertir x duplicar, hacer cálculos, a continuación, convertir resultado de nuevo a flote. Ventajas y desventajas de este tipo de comportamiento:

Pros: ganancia

  • precisión debido a cálculos reales se harán en doble precisión.

Contras:

  • Si el rendimiento es un problema, esto podría dar como resultado más rápido, así como ejecución más lenta, dependiendo del entorno y la plataforma. Este introduce algún cambio de rendimiento en función de la implementación, que es, en lo que a mí respecta, malo.
  • Presenta incoherencias en los cálculos porque algunas operaciones serán realizadas en flotantes y algunas en dobles, dependiendo del uso de literales. Este también podría provocar la exposición de algunos errores.
  • Se rompe la idea de especializar la clase para carrozas en el primer lugar porque de todos modos los cálculos se realizarán en dobles.

En conclusión, el objetivo es hacer que la creación de instancias de clase funcione en los tipos adecuados sin conversiones adicionales. La idea de usar literales de doble tipo en todas partes, como 0.5 y dejar manejar la conversión adecuada al compilador no es una opción.

Más sobre el tema: Should we generally use float literals for floats instead of the simpler double literals?

soluciones posibles?

  • métodos especializarse para cada plantilla de tipo de instancias donde literales tienen que ser utilizados. Esta es probablemente la peor solución porque obliga a escribir el mismo código dos veces con cambios menores en los literales .
  • Haga los métodos especializados getValue<type>(), o como Jonathan Wakely posted - miembros especializados. Esto puede llevar a tener algunos miembros o métodos con nombres tontos en la clase, como getZeroPointFive<float>().
  • Mohammad y Tony Delroy señalaron que ajustar cada literal con static_cast<T>() hará el truco. La conversión al tipo correcto será hacerse en tiempo de compilación.
+0

Ha surgido una mejor solución ... comentario de Mohammad ... emitiendo los valores antes de que participen en las expresiones ala static_cast (5.0).Sé que no te gusta, pero va a ser un tiempo de compilación y está localizado con el número, mientras que getZeroPointFive, etc. –

+0

Gracias por señalarlo. Lo he agregado a posibles soluciones – umebe

Cuestiones relacionadas