Este problema ha sido discutido un par de veces pero todas las soluciones que he encontrado no funcionan o se basa en impulsar la estática de la aserción. Mi problema es simple. Tengo una clase, y yo sólo quiero permitir que los tipos reales (double y float). Quiero un error en tiempo de compilación si intento crear una instancia de la clase con un tipo distinto de float o double. Estoy utilizando Visual C++ 11. Aquí es lo que he intentado:

template <typename RealType>
class A
{
  //Warning C4346
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value);
}


template <typename RealType>
class A
{
  //Error C2062: type 'unknown' unexpected
  static_assert(decltype(RealType) == double || decltype(RealType) == float);
}

Alguna idea? Gracias de antemano!

  • La primera pregunta es, ¿importa? Si se crea la instancia de la plantilla con otro tipo, y el tipo no pueden ser tratadas de la manera en la plantilla de espera para tratar de compilación fallará. Y si se puede, permitiendo que sólo los dos tipos efectivamente forajidos…digo…un tipo como BigDecimal.
  • visual studio realmente emitir una advertencia cuando static_assert falla, y no un error? Suena como un error.
  • Véase también las plantillas de C++ que acepte sólo ciertos tipos y Restringir C++ Parámetro de Plantilla para la Subclase. Ellos son anteriores a la de C++11, pero que podría ser un buen marcador para alguien más.
InformationsquelleAutor quant | 2013-06-07

3 Comentarios

  1. 21

    Una solución que he visto es el uso de std::enable_if en un alias de tipo. Algo así como:

    using value_type = typename std::enable_if<
                        std::is_same<float, RealType>::value ||
                        std::is_same<double, RealType>::value,
                        RealType
                    >::type;

    value_type sólo existe si RealType es exactamente float o double. De lo contrario, el tipo es indefinido y la compilación falla.

    Me gustaría advertir sobre ser demasiado estricto con los tipos, aunque. Las plantillas son tan poderosos como ellos son, en parte porque el pato escritura que hacen significa que cualquier tipo que se puede utilizar de la manera que usted quiere usar, va a trabajar. Deshabilitando los tipos por el bien de interceptar los tipos generalmente no aumenta mucho, y puede hacer que las cosas menos flexible de lo que podrían ser. Por ejemplo, usted no será capaz de utilizar un tipo con más precisión, como un gran tipo decimal.

    • Eso, y si sólo se necesitan dos especializaciones, buen viejo OO y el polimorfismo en tiempo de ejecución podría ser una buena idea (al menos vale la pena considerar).
    • SFINAE es muy bueno cuando se quiere crear más especializaciones de la plantilla 🙂 sin Embargo, si zhe seguro nunca va a ser cualquier otra especialización, static_assert permite mostrar mensajes de error significativos (porque SFINAE suelen lastimar mis ojos).
  2. 29

    En el primer ejemplo, static_assert debe tomar un segundo parámetro que sería un literal de cadena, de lo contrario, se considerará a fallar (edición: caer el segundo parámetro es legal, ya que C++17). Y este segundo argumento no puede ser predeterminada.

    El segundo ejemplo es incorrecta por varias razones:

    • decltype está destinado a ser utilizado en una expresión, no en un tipo.
    • Simplemente no se puede comparar tipos con ==, la forma correcta de hacer esto es lo que intenta en su primer intento con std::is_same.

    Así, la forma correcta de hacer lo que estamos tratando de lograr es:

    #include <type_traits>
    
    template <typename RealType>
    class A
    {
      static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value,
                    "some meaningful error message");
    };

    Además, apuesto a que usted está tratando de estrechar su plantilla flotante valor de puntos. Con el fin de hacer esto, puede utilizar la característica std::is_floating_point:

    #include <type_traits>
    
    template <typename RealType>
    class A
    {
      static_assert(std::is_floating_point<RealType>::value,
                    "class A can only be instantiated with floating point types");
    };

    Y como un bono, tomar este ejemplo en línea.

  3. 5

    De esta manera también permite la especialización de varios tipos:

    template<typename T, typename Enable = void>
    class A {
    ///Maybe no code here or static_assert(false, "nice message");
    };
    
    ///This specialization is only enabled for double or float.
    template<typename T>
    class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> {
    
    };
    • con static_assert(false, "nice message"); el programa está mal formado, no diagnósticos requeridos. Consulte stackoverflow.com/questions/30078818/… El problema que hay al principio parece más compleja, pero el subrayado causa es tan simple como el ejemplo.

Dejar respuesta

Please enter your comment!
Please enter your name here