A Coder’s Corner

Blog de tecnologia y programación

Archive for May, 2007

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. 🙂

Posted in C++ | 6 Comments »

Lambda Functions

Posted by gfaraj on May 24, 2007

En lenguajes de programacion, lambda expressions basicamente son funciones que se definen en el lugar de su uso y se pueden usar como “objetos” en el sentido que se pueden asignar a una variable y llamarlas en otro punto del programa. Para una definicion mas completa de lambda functions visiten: http://en.wikipedia.org/wiki/Lambda_expressions.

Las lambda functions estan presentes en varios lenguajes, como Eiffel, C#, Java, y proximamente en C++. C++ tiene Boost.Lambda, que es una libreria que trata de proveer esta funcionalidad. Veamos ejemplos en algunos de estos lenguajes.

C#
En C# existen los delegates que encapsulan funciones para que puedan ser usadas como objetos. Como ejemplo, consideremos una funcion que es llamada cuando un boton es clickeado:

public MyForm()
{
    button = new Button();
    // ...
    button.Click += new EventHandler(button_Click);
}

private void button_Click(object sender, EventArgs e)
{
    button.Text = "Hola";
}

Usando lambda functions, esto se convierte a:

public MyForm()
{
    button = new Button();
    // ...
    button.Click += delegate
    {
        button.Text = "Hola";
    }
}

Como ven, para cosas sencillas es muy util ya que no tenemos que definir una funcion aparte.

Java
En Java, es un poco mas complicado ya que lo que se define es una clase, y no una funcion. Por ejemplo:

Button button = new Button();
button.addActionListener(new ActionListener()
{
    public void onActionPerformed(ActionEvent e)
    {
        button.setLabel("Hola");
    }
});


C++
(con Boost.Lambda)
En C++ no hay nada en el lenguaje que permita definir un lambda expression. En la actualidad, C++ te deja pasar el puntero a una funcion y llamarla asi de otro lugar. Mucho trabajo se ha invertido para poder encapsular funciones en objetos para que sean mas util (vean Boost.Function y Boost.Bind). Un ejemplo es imprimir cada elemento de un vector:

void print(int x)
{
    std::cout << x << std::endl;
}

int main()
{
    std::vector<int> v(10);
    for_each(v.begin(), v.end(), &print);
}

Ahora usando Boost.Lambda:

int main()
{
    std::vector<int> v(10);
    for_each(v.begin(), v.end(), std::cout << _1 << std::endl);
}

El _1 es un objeto que actua como “placeholder” para el primer parametro de la funcion. Es una libreria muy limitada por el lenguaje, por eso no es de tanta utilidad como si el lenguaje soportara esto nativamente.

C++0x
Para el proximo estandar de C++ se van a agregar funciones lambda reales. Veamos el ejemplo anterior con el nuevo sintaxis:

int main()
{
    std::vector<int> v(10);
    for_each(v.begin(), v.end(), <>(int x)
    {
        std::cout << x << std::endl;
    });
}

En resumen, las lambda functions nos ayudan a reducir el codigo necesario para hacer una funcion sencilla que pueda ser pasada a funciones y tratada como un objeto. Es una caracteristica popular entre varios lenguajes de programación.

Posted in Programación | Leave a Comment »

Visual Studio 2007 – Orcas

Posted by gfaraj on May 17, 2007

Para los que todavia no sabian, el Beta del Visual Studio 2007 (codename Orcas) está disponible en la pagina de Microsoft. Segun la descripción, mejora el desarrollo para Windows Vista, Office 2007 y Web. No se exactamente que cosas le agregaron porque todavia no lo he instalado, pero cuando lo instale daré un review más extenso. Para los que no les gusta bajar Beta software y todavia no saben del VC++ 2005 Express, lo pueden bajar gratis tambien. Es un muy buen compilador de C++ para los que no podemos conseguir un compilador de los pagados.

Los que lo quieran bajar el VC++ 2005 Express manualmente, click aqui (gracias jfontecha).

Posted in C++, Tecnologia | 8 Comments »

Initializer Lists

Posted by gfaraj on May 17, 2007

Las listas inicializadoras (sin confundiras con las listas de inicialización del constructor) es una caracteristica que va a ser agregada al nuevo estandar de C++. Permitirá la inicialización de clases usando una lista de inicialización como arreglo.

std::vector<int> v = {4, 10, 1, 20};

struct X
{
    int arreglo[3];

    // esta inicializacion no es posible ahorita
    X() : arreglo({1,2,3}) {}
};

Esta caracteristica y la agregación de la clase std::array a la libreria estandar practicamente quitan cualquier necesidad de usar arreglos puros. Veamos como podrian hacer que sus clases puedan ser inicializadas asi.

class MiClase
{
public:
    MiClase(std::initializer_list<int> s)
    {
        for (auto it = s.begin(); it != s.end(); ++it)
            std::cout << *it << " ";
    }
};

MiClase clase = {1, 30, 21, 30, 1};

Como pueden ver, solo tienen que proveer un constructor que tome un initializer_list para obtener esta funcionalidad. Como es esperado, el codigo de arriba imprime 1 30 21 30 1.

Esta caracteristica es un paso más hacia adelante para hacer C++ más flexible y limpio. Hay muchas propuestas como esta que buscan simplificar el codigo que hay que escribir para cosas triviales.

Posted in C++0x | 1 Comment »

Templates de C++ – Specializations

Posted by gfaraj on May 10, 2007

Hoy les hablaré un poco más de los templates de C++. Las especializaciones o specializations permiten que el programador defina un template diferentemente para un tipo especifico. Por ejemplo, una funcion que retorna verdadero si el parametro es un int o falso si no lo es:

template <typename T>
bool es_int()
{
    return false;
}

template <>
bool es_int<int>()
{
    return true;
}

int main()
{
    std::cout << es_int<int>() << std::endl;
    std::cout << es_int<bool>() << std::endl;
}

El primer template es el que se le llama el base template y el segundo es una especialización del mismo. Si corren el programa van a ver que imprime 1 en la primera linea y 0 en la segunda. Es un concepto muy util que nos permite hacer cosas bien interesantes. Tambien se puede aplicar a templates de clases.

template <typename T>
class MiClase
{
};

template <>
class MiClase<int>
{
private:
    MiClase();  // constructor privado
};

int main()
{
    MiClase<bool> c1;  // todo bien
    MiClase<int> c2;   // error: el constructor es privado!
}

Este ejemplo muestra como se puede prevenir que se use un template si se quiere usar con algun tipo especifo. Al igual que las funciones, el primero se llama el base template y el segundo es una especialización. Al declarar el constructor de MiClase<int> como privado, el compilador no te deja crear una instancia de el.

Basicamente asi es como se especializa una funcion o una clase template. Talvez no le vieron la gran utilidad con estos ejemplos, pero se usa extensivamente en Boost para crear cosas muy utiles. Otro dia vendré con aplicaciones más interesantes de este concepto. 🙂

Posted in C++ | Leave a Comment »

Smart Pointers

Posted by gfaraj on May 8, 2007

Un “smart pointer” es un pointer que sabe cuando debe borrarse y lo hace. Usarlos en vez de punteros crudos podria salvarles mucho tiempo de debugging, pero usarlos mal les podria extender ese tiempo. Los que estan implementados en Boost estan bien hechos y son thread-safe. Les recomendaria usar esos en vez de implementar una version propia, ya que estos son probados exhaustivamente.

Voy a hablar sobre dos tipos de smart pointers: el scoped pointer y el shared pointer. El primero no se puede copiar; como dice su nombre, se usa en un “scope.”

{
    boost::scoped_ptr<MiClase> ptr1(new MiClase);
    ptr1->foo();

    {
        boost::scoped_ptr<int> ptr2(new int);
        *ptr2 = 10;
        // ptr2 se destruye aqui
    }

    // ptr1 se destruye aqui
}

A simple vista, se puede observar la utilidad de esta clase. No nos tenemos que preocupar por llamar delete despues de usar el puntero. Pero, también tiene una caracteristica muy buena que talvez sea mas dificil de ver. Si ptr1->foo(); tira un exception, este codigo no produciria un leak de memoria ya que el destructor de ptr1 se llamara y destruira el puntero. Con punteros crudos habria que poner un try-catch y borrar el puntero en el catch para que el codigo sea igual de correcto.

El otro tipo de smart pointers que voy a presentar es el shared pointer. Este si se puede copiar, y lo que hace es que mantiene un “reference count” de cuantas veces ha sido copiado. Se borra el puntero hasta que la ultima copia se haya destruido (o sea cuando el count llega a 0).

{
    boost::shared_ptr<MiClase> ptr1(new MiClase);
    ptr1->foo();

    {
        boost::shared_ptr<MiClase> ptr2(ptr1);
        ptr2->foo();
        // decrementa el reference count
    }

    // decrementa el reference count
    // borra el puntero
}

La utilidad que agrega esta clase a la del scoped pointer es que esta si la podemos copiar. Si se ocupa que un puntero sea compartido entre varias clases o modulos, usar esta clase es ideal. La razon es que el shared_ptr no va a dejar que el puntero muera hasta que todas las copias se hayan destruido, asi que es mas seguro. Claro, hay que tener cuidado y usar correctamente esta clase.

{
    MiClase* puntero = new MiClase;

    boost::shared_ptr<MiClase> ptr1(puntero);
    boost::shared_ptr<MiClase> ptr2(puntero);

    // boom! el mismo puntero se borro dos veces
}

Tambien existe el problema de la referencia circular. Prueben el siguiente codigo y veran que ningun destructor se ejecuta.

struct B;

struct A
{
    ~A() { std::cout << "~A()"; }
    boost::shared_ptr<B> ptrB;
};

struct B
{
    ~B() { std::cout << "~B()"; }
    boost::shared_ptr<A> ptrA;
};

int main()
{
    boost::shared_ptr<A> ptr(new A);
    ptr->ptrB.reset(new B);
    ptr->ptrB->ptrA = ptr;

    // ninguno se destruye
}

Usandolas correctamente, estas clases nos pueden hacer la vida mucho más facil. El codigo producido al usar estas clases es más robusto y seguro.

Posted in Boost | 1 Comment »

Decltype y auto

Posted by gfaraj on May 6, 2007

Dos keywords se van a introducir al nuevo estandar de C++: decltype y auto. Estos dos keywords serviran para poder deducir el tipo de una expresion, cosa que no se puede hacer en el estandar de ahora. Aqui hay un ejemplo de decltype:

int a;
bool& b;

int foo(float);

decltype(a)          // int
decltype(b)          // bool&
decltype(foo)        // int (float)
decltype(foo(1.0f))  // int
decltype(1+3)        // int

El operador decltype crea un tipo analogo al que se crea usando typedef. Este operador ayudará bastante a que la programación generica sea mas fácil y poderosa, ya que sin saber de que tipo son a y b, podemos saber de que tipo es una expresion como a + b usando decltype(a+b). El operador auto ayudará en situaciones similares también. Veamos un ejemplo.

auto a = 10;       // int a = 10;
auto b = a + 2.3;  // double b = a + 2.3;

std::vector<int> vec;
for (auto it = vec.begin(); it != vec.end(); ++it)
   std::cout << *it << endl;

En el ultimo ejemplo se puede apreciar un poco la utilidad de este operador, nos ahorra la necesidad de escribir tipos muy largos y sirve para darle un poco de limpieza al codigo. En vez de auto it = vec.begin() hubiera tenido que ser std::vector<int>::iterator it = vec.begin(). El operador auto se podria implementar en terminos del operador decltype. Por ejemplo:

// int a = 10;
auto a = 10;
decltype(10) a = 10;

// std::vector<int>::iterator it = vec.begin();
auto it = vec.begin();
decltype(vec.begin()) it = vec.begin();

Pero podrian ver que el uso de decltype en esos casos resulta en duplicación de codigo, asi que usar auto conviene mas en estos casos. A los que les interesa saber más sobre estas nuevas caracteristicas, entren aqui para ver un resumen de lo ultimo que esta pasando. Tambien, aqui hay una lista de los articulos que se publican.

Posted in C++0x | Leave a Comment »

Windows Live Writer – Beta

Posted by gfaraj on May 4, 2007

Microsoft esta lanzando un programa para postear articulos facilmente a tu blog. Lo interesante es que lo puedes usar con varios sitios de blogs como Blogspot, Live Spaces y WordPress (estoy usandolo para postear este mismo articulo).

El Windows Live Writer tambien tiene un editor mas amigable que muchos de los sitios de blogging. Te permite pegar una imagen simplemente tecleando Ctrl+V. Te deja ver un preview de como se va a ver exactamente en el blog (con todos los estilos puestos). Puedes bajar plugins para extender su funcionalidad. Por ejemplo, yo baje el “Paste from Visual Studio” plugin. En el post anterior pueden ver que el codigo que puse esta coloreado como esta en Visual Studio. Solo tuve que copiar el codigo del Visual Studio y clickear en “Insert from Visual Studio…” y el codigo aparecio coloreado en Live Writer. Se los recomiendo! 😉

Posted in Tecnologia | 1 Comment »

Boost.Function + Boost.Bind

Posted by gfaraj on May 3, 2007

La combinación de Boost.Function y Boost.Bind es la que más utilizo de Boost. Son librerias que encapsulan funciones y las dos se usan de la par. La primera guarda una funcion generica de cierto prototipo, la segunda se usa de adaptador que actua como una funcion. Empecemos con un ejemplo de Boost.Function:

void foo();

int main()
{
    // queremos guardar una funcion con resultado void y sin parametros
    boost::function<void ()> func = foo;
    func();
}

Ahi pueden ver un ejemplo sencillo de como usar boost::function, aunque poco util en este ejemplo. Lo interesante que veremos adelante es que tambien podemos guardar funciones miembros a la par de funciones normales, algo que no se puede hacer con simples punteros a las funciones. Aqui es donde entra boost::bind.

void foo();

class Bar
{
public:
    void baz();
};

int main()
{
    boost::function<void ()> func = foo;
    func();

    Bar bar;
    func = boost::bind(&Bar::baz, &bar);
    func();
}

En el ejemplo pueden ver que se puede usar el mismo objeto para guardar una funcion normal y una funcion miembro. Esto es muy util para cuando se ocupan “callbacks.” De costumbre, las APIs hechas en C cuando ocupan un callback se tiene que pasar un puntero a una funcion normal y ademas proveer un campo denominado “user data” que por lo general es un void*. Esto puede ser inseguro y es muy tedioso. Aqui vemos que no es nada del otro mundo usar los objetos de Boost. Para finalizar voy a poner codigo ilustrando otras aplicaciones de estas clases.

void foo(int x, bool y);

class Bar
{
public:
    void baz();
};

int main()
{
    // llamar una funcion de cada objeto en un vector
    std::vector<Bar> v1(10);
    std::for_each(v1.begin(), v1.end(), boost::bind(&Bar::baz, _1));

    bool r = true;
    boost::bind(foo, 10, _1)(r);      // foo(10, r);

    int s = 30;
    boost::bind(foo, _1, false)(s);   // foo(s, false);
    boost::bind(foo, _1, _2)(s, r);   // foo(s, r);
}

El _1 y el _2 son “placeholders” que ocupan el espacio del primer y el segundo parametro de la funcion, respectivamente. Espero que les haya gustado, y si les gusto talvez les guste Boost.Signal que es una libreria mas especificamente para manejar “callbacks” ya que un objeto puede almacenar varias funciones, no solo una. Igual, funciona bien a la par de Boost.Function y Boost.Bind.

Posted in Boost | 3 Comments »

Boost – Herramienta Esencial

Posted by gfaraj on May 3, 2007

Boost es una libreria general para C++ que contiene muchas cosas esenciales para el desarrollo de software con este lenguaje. Desde manejar el filesystem, usar regular expressions y serializacion hasta hilos, utilidad de fechas y “smart pointers,” esta libreria es muy util. Todo programador de C++ deberia tener esta herramienta a su disposición ya que los desarrolladores de Boost trabajan duro para hacer que funcione en muchas plataformas y compiladores. Ademas, muchas de sus caracteristicas seran adoptadas por el siguiente estandar de C++.

Estaré discutiendo las caracteristicas mas importantes de Boost en este blog.

Posted in Boost | 3 Comments »