2012-02-16 13 views
5

Tengo un conjunto de funciones que se en plantillas tanto por un tipo entero Index y un tipo de clase T, que I "parcialmente especializo" de la siguiente manera:La elección de una de instancias de plantilla en tiempo de ejecución, aunque cambiar en C++

// Integer type 
enum Index{One,Two,Three,Four}; 

// Default implementation 
template<int I> 
struct Foo{ 
    template<typename T> static void bar(const T& x){ std::cout <<"default" << endl; } 
}; 

// Template specializations 
template<> 
struct Foo<One>{ 
    template<typename T> static void bar(const T& x){ std::cout << "one" << endl; } 
}; 

Esto lo utilizo para seleccionar un índice en particular en el tiempo de ejecución del programa usando una declaración de cambio (que debe resultar en una tabla de búsqueda eficiente). El interruptor es independiente de T:

template<typename T> 
void barSwitch(int k, const T& x){ 
    switch(k){ 
    case ONE: Foo<ONE>::bar(x); break; 
    case TWO: Foo<TWO>::bar(x); break; 
    case THREE: Foo<THREE>::bar(x); break; 
    } 
} 

Esto funciona bien, por supuesto, pero la clase Foo no es la única clase en la cual me gustaría solicitar el cambio. De hecho, tengo muchas clases que tienen todas las plantillas con el mismo tipo de entero. Así que me gustaría "plantilla" la clase barSwitch anterior con la función "Foo" también, para que pueda conectar una clase diferente o una función diferente. La única manera que puedo pensar para lograr esto es utilizar una macro:

#define createBarSwitch(f,b) \ 
template<typename T> \ 
void barSwitch(int k, const T& x){ \ 
    switch(k){ \ 
    case ONE: f<ONE>::b(x); break; \ 
    case TWO: f<TWO>::b(x); break; \ 
    case THREE: f<THREE>::b(x); break; \ 
    }\ 
} 

¿Hay alguna forma mejor estilo, más C++ de hacer esto?

+0

Si desea parametrizar por tipo de functor, consulte la discusión de functors aquí: http://stackoverflow.com/q/356950/183203 – antlersoft

+0

Estoy seguro de que se da cuenta de que no puede realizar funciones parcialmente y que está totalmente especializado en el objeto 'Foo', pero tal vez busque en una clase de rasgos o en el modismo int-to-type para elegir la instanciación que desee. Las sobrecargas pueden ser más simples. – AJG85

+0

Correcto, sé que no es realmente una especialización parcial. Solo quise decir que especializo el tipo entero, pero mantengo el tipo 'T' no especificado. – Joel

Respuesta

6

parámetros de plantilla plantilla son la clave:

enum Index { One, Two, Three, Four }; 

template <template <Index> class Switcher, typename T> 
void barSwitch(int k, const T & x) 
{ 
    switch (k) 
    { 
     case 1: Switcher<One>::template bar<T>(x); break; 
     case 2: Switcher<Two>::template bar<T>(x); break; 
     default: assert(false); 
    } 
} 

Uso:

template <Index I> struct Foo 
{ 
    template <typename T> static void bar(const T & x); 
}; 

barSwitch<Foo>(1, Blue); 

(Es su responsabilidad asegurarse de que todas las plantillas posible que usted sustituto de Switcher tiene una plantilla miembro de bar, de Por supuesto, si no, obtendrá un error de compilación.)

+0

¡Bonito! Eso lo resolvió, gracias! – Joel

0
template<template<int> class F> 
struct BarFunc {}; 


template<> 
struct BarFunc<Foo> { 
    template<Index I, typename T> 
    static void call(const T& x) { 
     Foo<I>::bar(x); 
    } 
}; 


template<template<int> class F, typename T> 
void barSwitch(int k, const T& x) { 
    switch(k){ 
    case One: BarFunc<F>::call<One>(x); break; 
    case Two: BarFunc<F>::call<Two>(x); break; 
    case Three: BarFunc<F>::call<Three>(x); break; 
    } 
} 

Puede parametrizar a qué función desea llamar proporcionando una especialización BarFunc.

Cuestiones relacionadas