que - codigos de c++ y sus funciones
restringiendo el uso de plantillas de c++ a los tipos de POD (5)
Con type_traits, y static_assert, es bastante fácil:
#include <type_traits>
struct A{
};
struct B{
virtual ~B(){}
};
template< class T >
struct MyClass
{
static_assert( std::is_pod<T>::value, "not a POD" );
};
int main()
{
MyClass<A> a;
//MyClass<B> b; -- break, cause not a POD
}
Tengo una clase de plantilla de C ++, que solo funciona correctamente si el tipo de plantilla es datos antiguos. Cualquier cosa con un constructor que haga algo no funcionará correctamente.
Me gustaría obtener de alguna manera una advertencia de tiempo de ejecución o de tiempo de ejecución cuando alguien intenta hacerlo de todos modos.
//this should generate error
myclass<std::string> a;
//this should be fine
myclass<int> b;
¿Hay un truco para hacer esto?
Mientras que static_assert
probablemente sea suficiente en la mayoría de los casos, el uso de enable_if
y el envío de etiquetas le da mayor flexibilidad a los usuarios de su clase por las formas de SFINAE. Considerar:
#include <type_traits>
#include <string>
#include <iostream>
template <typename T,
class=typename std::enable_if< std::is_pod<T>::value >::type>
struct myclass
{
typedef T value_type;
T data;
};
template <typename T>
void enjoy(T)
{
std::cout << "Enjoying T!" << std::endl;
}
template <typename T>
void enjoy(typename myclass<T>::value_type)
{
std::cout << "Enjoying myclass<T>::value_type!" << std::endl;
}
int main()
{
enjoy<int>(int()); // prints: Enjoying myclass<T>::value_type!
enjoy<std::string>(std::string()); // SFINAE at work - prints: enjoying T!
myclass<int> i; // compiles OK
//myclass<std::string> s; // won''t compile - explicit instantiation w/non-POD!
}
Ahora, si elimina el argumento de la 2ª plantilla de la definición de myclass
y, en su lugar, como otros han sugerido, agregue un
static_assert(std::is_pod<T>::value, "POD expected for T");
dentro de la clase, la segunda línea en main()
simplemente no podrá compilarse, lo que activará static_assert.
Dicho esto, los errores de static_assert
son mucho más amigables para el observador humano que los enable_if
. Por lo tanto, si static_assert
funciona para ti, hazlo. De lo contrario, si necesita ser más amigable con la programación genérica de su clase, considere agregar un comentario explicativo alrededor de enable_if
:
// POD expected for T
class=typename std::enable_if< std::is_pod<T>::value >::type>
a menos que todos a tu alrededor sean C ++ 11-fluidos.
En la vida real, es una buena idea explicar por qué T debe ser POD tanto para static_assert
como para los textos de comentarios.
Si tiene soporte para C ++ 11, std :: is_pod debe hacer exactamente lo que necesita. Úselo con std :: enable_if o con el envío de etiquetas. Por ejemplo algo como esto:
template <typename T, typename Enable = void>
class Test;
template<typename T>
class Test<T, typename std::enable_if<std::is_pod<T>::value, void>::type>
{};
int main() {
Test<int> t1;
//Test<std::string> t2; <-this will not compile
}
Si no tienes C ++ 11
Si los tipos de POD objetivo son limitados ( int
, float
, ...), puede poner la implementación en un archivo .cpp
y crear una instancia explícita para ese tipo de archivos:
archivo .h
:
template <typename T>
class myclass
{
T data;
public:
void func();
};
archivo .cpp
:
#include "myclass.h"
template <typename T>
void myclass<T>::func()
{
}
template class myclass<float>;
template class myclass<int>;
template class myclass<char>;
...
Después de eso, myclass
solo se puede usar para esos tipos y los descansos para otros.
#include <type_traits>
template<typename T>
class myclass
{
static_assert(std::is_pod<T>::value, "T must be POD");
// stuff here...
};
Lo anterior causará un error de compilación si pasa un tipo no POD como parámetro de plantilla. Esta solución requiere C ++ 11 para el <type_traits>
y la palabra clave static_assert
.
EDITAR: También puede implementar esto en C ++ 03 si su compilador soporta TR1 (la mayoría lo hace):
#include <tr1/type_traits>
template<typename T>
class myclass
{
static char T_must_be_pod[std::tr1::is_pod<T>::value ? 1 : -1];
// stuff here...
};