2011-06-02 12 views
7

Estoy creando una clase de plantilla D<N>, con un método (operador(), en este caso) que devuelve diferentes tipos, dependiendo del valor de N.Duplicación de código y especialización de plantilla (cuando la función especializada tiene diferentes tipos de retorno)

Solo pude hacer que esto funcionara al crear dos declaraciones de clases separadas, pero esto tuvo el costo de una gran cantidad de duplicación de código. También traté de crear una clase base común de tirar las cosas en común, pero no pude conseguir el constructor para heredar la derecha y no sé cómo idiomática que sería así ...

#include <cstdio> 

template <int N> 
struct D{ 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 

    D<N-1> operator()(int x){ 
     D<N-1> d(yell(x)); 
     return d; 
    } 
}; 

template <> 
struct D<1>{ 
    int s; 
    D(int x): s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", 1, s+x); 
     return s+x; 
    } 

    int operator()(int x){ 
     return yell(x); 
    } 
}; 


int main() 
{ 
    D<2> f(42); 
    printf("%d\n", f(1)(2)); 
    return 0; 
} 

Cómo ¿Puedo hacer que mi código se vea mejor?

+0

Es necesario reconsiderar la utilidad del tipo de retorno que depende del valor de los parámetros. Haga que sea un tipo de retorno polimórfico consistente o descubra una forma sensata de devolver siempre un tipo básico. En situaciones como esta, generalmente me resulta útil volver a las necesidades básicas de la aplicación. – wallyk

+0

El problema es que no hay un buen tipo para codificar listas de cierta longitud. Hacer la magia negra de plantilla permitiría que mi pequeña DSL fuera agradable de usar y también segura. – hugomg

+0

¿Necesita una lista vinculada de "compilación de la duración del tiempo"? ¿No es std :: array/boost :: array adecuado para su caso? La desventaja es que no puede tomar un objeto de "subcampo", pero también puede usar la "interfaz de longitud variable de tiempo de ejecución" (iteradores, [], puntero ...). – ysdx

Respuesta

8

Puede utilizar el Patrón de plantilla curiosamente recurrente.

template<int N, template<int> typename D> struct d_inner { 
    D<N-1> operator()(int x) { 
     return D<N-1>(static_cast<D<N>*>(this)->yell(x)); 
    } 
}; 
template<template<int> typename D> struct d_inner<1, D> { 
    int operator()(int x) { 
     return static_cast<D<1>*>(this)->yell(x); 
    } 
}; 

template <int N> struct D : public d_inner<N, D> { 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
     printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 
}; 

No es que ver la red- o de un propósito-de este objeto particular que se está templated, que fácilmente podría no serlo.

+0

+1 para "No es que yo vea la utilidad o el propósito de este objeto en particular ser modelado, podría no serlo fácilmente" – fedvasu

4

no estoy seguro de que es mejor buscando: pero evita la duplicación de código fuente:

// Find a name for this ... 
template<int N, template<int M> class X> 
struct foo { 
    typedef X<N> type; 
}; 
template< template<int M> class X > 
struct foo<0,X> { 
    typedef int type; 
}; 

template <int N> 
struct D{ 
    int s; 
    D(int x):s(x){} 

    int yell(int x){ 
    printf("N=%d, %d\n", N, s+x); 
     return s+x; 
    } 

    typename foo<N-1,D>::type 
    operator()(int x){ 
    return typename foo<N-1,D>::type(yell(x)); 
    } 
}; 
Cuestiones relacionadas