Tengo un método que toma un objeto como parámetro.
void fun(const Obj& obj)
Obj
Se puede definir de dos maneras diferentes:
struct Obj
{
Type x;
};
y
struct Obj
{
Type x[42];
};
No puedo modificar las definiciones de Obj
(es decir, no puedo cambiar el nombre de las clases). Además, no puedo modificar la firma de fun
y preferiría no usar directivas de preprocesador dentro de fun
. ¿Hay una manera de usar metaprogramación para hacer esta compilación y trabajo independientemente de qué definición de Obj
está incluido:
void fun(const Obj& obj)
{
impl(obj); // executes some code if obj.x is an object
// executes some other code if obj.x is an array
}
? ¿Hay alguna manera de hacerlo sin las características de C ++ 11?
Respuestas
2 para la respuesta № 1Podrías elegir una especialización de una plantilla basada en decltype(obj.x)
:
template<typename T>
void impl(const Obj&);
template<>
void impl<Type>(const Obj&) {}
template<>
void imp<Type[42]>(const Obj&) {}
void fun(const Obj& obj)
{
impl<decltype(obj.x)>(obj);
}
La posible forma de C ++ 03 es una clase de rasgo de detector miembro que verifica la existencia de Type Obj::x
. Esta vez, el parámetro de plantilla de impl
sería bool
por lo que simplemente puede pasar el resultado del cheque:
template<typename C>
struct has_Type_x {
template<typename U, U>
struct Check;
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename> static no test(...);
template<typename U> static yes test(Check<Type U::*, &U::x>*);
static const bool value = sizeof(test<C>(0)) == sizeof(yes);
};
template<bool> void impl(const Obj&);
template<>
void impl<true>(const Obj&) {}
template<>
void impl<false>(const Obj&) {
std::cout << "arr";
}
void fun(const Obj& obj)
{
impl< has_int_x<Obj>::value >(obj);
}
1 para la respuesta № 2
Esto se puede hacer mediante una segunda llamada a una función de implementación fun_impl
que tambien toma obj.x
como argumento Esta función se especializa en escalar o matrices por dos sobrecargas, esta última acepta una referencia a una matriz, manteniendo así el tamaño de la matriz:
template <typename Obj, typename T>
void fun_impl(const Obj& obj, const T& x) {}
template <typename Obj, typename T, size_t N>
void fun_impl(const Obj& obj, const T (&x)[N]) {}
template <typename Obj>
void fun(const Obj& obj)
{
fun_impl(obj, obj.x);
}
Esto funciona en C ++ 03 y no requiere ninguna característica de rasgos o SFINAE. Ver también ejemplo vivo, donde las partes restantes usan C ++ 11 por conveniencia.
Si obj
solo contiene x
, puedes dejarlo como un argumento de fun_impl
. Lo dejé aquí para el caso más general donde obj
podría tener otros miembros también.
Tenga en cuenta que fun
se da aquí como una plantilla; Supongo que esto es lo que debe hacer de todos modos, ya que está tratando con diferentes definiciones de Obj
.
0 para la respuesta № 3
Mi sugerencia es utilizar la sobrecarga de funciones. No necesita metaprogramación / plantillas en su caso:
void fun(const Obj& obj)
{
impl(obj.x);
}
void impl(const Type& x){...}
void impl(Type x[]){...}
Si Obj::x
se declara como Type x
entonces el primero impl()
Se llamará versión. Y similarmente en otro caso el segundo. impl()
Se llamará versión.