Si desea evitar la recursión de tipo manual, std::common_type
me parece ser la única utilidad en el STL que es una plantilla variadic, y por lo tanto la única que podría encapsular la recursión.
Solución 1
std::common_type
encuentra el tipo menos derivado en un conjunto de tipos. Si identificamos números con tipos, específicamente números altos con tipos menos derivados, encuentra el mayor número en un conjunto. Luego, tenemos que asignar la igualdad al tipo de clave en un nivel de derivación.
using namespace std;
struct base_one { enum { value = 1 }; };
struct derived_zero : base_one { enum { value = 0 }; };
template< typename A, typename B >
struct type_equal {
typedef derived_zero type;
};
template< typename A >
struct type_equal< A, A > {
typedef base_one type;
};
template< typename Key, typename ... Types >
struct pack_any {
enum { value =
common_type< typename type_equal< Key, Types >::type ... >::type::value };
};
Solución 2
Podemos cortar common_type
un poco más. El estándar dice
Un programa puede especializarse este rasgo si al menos un parámetro de plantilla en la especialización es un tipo definido por el usuario.
y describe exactamente lo que contiene: un caso de especialización recursiva parcial, un caso que aplica un operador binario y un caso de terminal. Esencialmente, es una función genérica fold
, y puede agregar cualquier operación binaria que desee. Aquí utilicé la suma porque es más informativo que OR. Tenga en cuenta que is_same
devuelve integral_constant
.
template< typename Addend >
struct type_sum { // need to define a dummy type to turn common_type into a sum
typedef Addend type;
};
namespace std { // allowed to specialize this particular template
template< typename LHS, typename RHS >
struct common_type< type_sum<LHS>, type_sum<RHS> > {
typedef type_sum< integral_constant< int,
LHS::type::value + RHS::type::value > > type; // <= addition here
};
}
template< typename Key, typename ... Types >
struct pack_count : integral_constant< int,
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {};
Puede ser un conjunto más grande de operaciones intrínsecas debe ser compatible con el lenguaje/compilador que simplemente sizeof .... (4 puntos!) IMO, verificar la existencia es tan "fundamental" como encontrar el tamaño. Siento que mpl tiene una sobrecarga de rendimiento basada en esta prueba que escribí. http://www.dre.vanderbilt.edu/~sutambe/files/mpl_intersection.cpp Estoy usando algoritmo de intersección codificado a mano, así como la versión de MPL. g ++ 4.4 toma el mismo tiempo para compilar ambos. La versión de plantillas variables compila 10 veces más rápido. Por cierto, ¿pueden sugerirme algo de lectura sobre la técnica de creación de instancias de plantillas perezosas de mpl? – Sumant
Encontré algunos buenos ejemplos de evaluación perezosa en el libro de metaprogramación de plantillas de C++. ¿No es obvio? Gracias de todos modos. – Sumant
Sí, todo lo que tiene que hacer es evitar la creación de instancias de plantillas de meta-funciones (al exponer el tipo de alias de tipo anidado ") antes de dar el resultado a otras metafunciones de impulso. Las meta-funciones de Boost se diseñaron para evaluar meta-funciones en el último momento es necesario el alias de tipo anidado. También debe intentar y evitar los valores desnudos y usar los envoltorios del tipo de metadatos (como mpl :: bool_) porque también están diseñados para funcionar perezosamente. Algunas veces impulsar mpl proporciona dos formas de una meta-función, intente utilizar la que promueve la creación de instancias perezosas. –