A Coder’s Corner

Blog de tecnologia y programación

Templates de C++ – Más Avanzado

Posted by gfaraj on May 29, 2007

Hace poco vimos como podiamos especializar un template en C++ para producir distintos resultados dependiendo de los parametros. Tomemos eso un paso más adelante y tratemos de hacer algo un poco más complicado: calcular el valor de un numero elevado a un poder, todo en tiempo de compilación.

// N^A
template <long N, unsigned int A>
struct pow
{
    static long const value = N * pow<N, A-1>::value;
};

// N^1 == N
template <long N>
struct pow<N, 1>
{
    static long const value = N;
};

// N^0 == 1
template <long N>
struct pow<N, 0>
{
    static long const value = 1;
};

int main()
{
    pow<10, 2>::value;      // 100
    pow<2, 3>::value;       // 8
    pow<1234, 0>::value;    // 1

    // un arreglo de 1024 elementos
    int arreglo[pow<2, 10>::value];
}

El base template representa al numero N elevado al poder A. Como pueden ver, es recursivo. Y como cualquier funcion recursiva, se ocupa un caso base para parar la recursion. Eso es lo que hacen las especializaciones de abajo, ya que sabemos que cualquier numero elevado al poder 1, es el mismo numero y cualquier numero elevado al poder 0 es siempre 1. El ultimo ejemplo muestra que el valor producido por pow se sabe al momento de compilar, asi que no hace nada en runtime. Eso si, puede que noten que tarda más en compilar.😀

Un ejercicio que sale en el libro C++ Template Metaprogramming (por cierto, muy bueno) consiste en crear una clase que por medio de templates y especializaciones describa en palabras el tipo pasado como parametro.

template <typename T>
struct type_descriptor
{
    template <typename OS>
    OS& write(OS& os) const { return os << "unknown-type"; }
};

template <>
struct type_descriptor<int>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "int"; }
};

template <>
struct type_descriptor<char>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "char"; }
};

template <>
struct type_descriptor<long>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "long"; }
};

template <>
struct type_descriptor<short>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "short"; }
};

template <typename T>
struct type_descriptor<T const>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "const " << type_descriptor<T>(); }
};

template <typename T>
struct type_descriptor<T volatile>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "volatile " << type_descriptor<T>(); }
};

template <typename T>
struct type_descriptor<T&>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "reference to " << type_descriptor<T>(); }
};

template <typename T>
struct type_descriptor<T*>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "pointer to " << type_descriptor<T>(); }
};

template <typename T>
struct type_descriptor<T[]>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "array of " << type_descriptor<T>(); }
};

template <typename T, int N>
struct type_descriptor<T[N]>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "array [" << N << "] of " << type_descriptor<T>(); }
};

template <typename R>
struct type_descriptor<R ()>
{
    template <typename OS>
    OS& write(OS& os) const { return os << "function returning " << type_descriptor<R>(); }
};

template <typename OS, typename T>
OS& operator<<(OS& os, type_descriptor<T> const & type)
{
    return type.write(os);
}

int main()
{
    using namespace std;

    cout << type_descriptor<int*>() << endl;
    cout << type_descriptor<long* (* const)()>() << endl;
    cout << type_descriptor<int volatile* const& (*[10])()>() << endl;
}

En este ejemplo, el base template no sabe que tipo le fue pasado, entonces regresa “unknown-type.” Despues, pueden ver que varias especializaciones han sido definidas. Estas son usadas para identificar el tipo exacto del parametro, y varias especializaciones son recursivas. El programa imprime lo siguiente:

pointer to int
const pointer to function returning pointer to long
array [10] of pointer to function returning reference to const pointer to volatile int

Es un buen ejercicio para empezar a pensar diferentemente acerca de los templates. Si les gusto, esperense para cuando hable del Metaprogramming Library.🙂

6 Responses to “Templates de C++ – Más Avanzado”

  1. MY NAME IS FRANCHESKA GUAD Y YOU FACE BOOK AND MYSPACE AND MESSELLE

  2. memmaker650 said

    MUy buenos ejemplos. Tenía muchas dudas con los templates y gracias a tus ejemplos me ha quedado muy claro todo. Es un tanto especial la definición de la recursividad en el primer ejemplo, sobre todo los que estamos acostumbrados a otros lenguajes.

    Gracias de nuevo.

  3. Dave4Teen said

    Hola amigo, tengo una duda. Como puedo hacer un rompcabezas, pero no usando cuadritos, sino formando las figuras de un rompezabezas real. Espero alguien me pueda ayudar

    Gracias y buen dia a todos

  4. This piece of writing is genuinely a fastidious one it assists new internet viewers, who are wishing for blogging.

  5. Very great post. I simply stumbled upon your weblog and wished to
    say that I have truly enjoyed browsing your blog posts.

    After all I will be subscribing for your rss feed and I’m hoping you write once more very soon!

  6. yahoo.com said

    Its like you read my mind! You seem to know a
    lot about this, like you wrote the book in it or something.
    I think that you could do with a few pics to drive
    the message home a bit, but other than that, this is fantastic blog.
    A fantastic read. I’ll definitely be back.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: