/ / Ejecutar código diferente para una clase que tenga un objeto o una matriz de objetos como miembro: c ++, templates, template-meta-programación

Ejecute un código diferente para una clase que tenga un objeto o una matriz de objetos como miembro: c ++, templates, template-meta-programación

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 № 1

Podrí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.