Facetas C++

Revisión del 22:35 20 jun 2019 de Javiermartin jc (discusión | contribuciones) (Texto reemplazado: «<div align="justify">» por «»)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Facetas C++
Información sobre la plantilla
Concepto:Las facetas C++ son clases muy flexibles (en realidad clases genéricas); también pueden ser definidas por el usuario o ser adquirida a terceros en forma de librería. Lo mismo que ocurría con los localismos C, las facet también se clasifican en seis categorías, y aunque en este caso los nombres no corresponden a constantes manifiestas, también corresponden a constantes enteras que rememoran muy de cerca los nombres utilizados en C : numeric; time; monetary; ctype; collate y message

La información y su manipulación, que en el caso de C está contenida en estructuras y en funciones globales, ha sido sustituida en C++ por unas clases denominadas facetas ("Facets") que derivan de una superclase facet. Un objeto facet puede contener prácticamente cualquier aspecto de internacionalización. Por ejemplo, el formato y símbolo de valores monetarios; los de fecha, Etc. le proporciona un par de docenas de estas clases que proporcionan servicios similares a los proporcionados por la librería Estándar C. Un facet encapsula la información local que en C está englobada en una categoría CL_..., aunque de forma más especializada. Por ejemplo, la funcionalidad contenida en la categoría LC_NUMERIC está dispersa en 4 facetas:

 template <class charT> class numpunct;
 template <class charT> class numpunct_byname;
 template <class charT, class InputIterator > class num_get;
 template <class charT, class OutputIterator> class num_put;

De estas clases existen espacializaciones para los tipos char y wchar_t, de forma que existen las siguientes:

numpunct<char>
numpunct<wchar_t>
numpunct_byname<char>
numpunct_byname<wchar_t>	num_get<char>
num_get<wchar_t>
num_put<char>
num_put<wchar_t>

Clasificación

Las facetas C++ se clasifican en seis categorías básicas representadas por constantes enteras cuyos nombres son los indicados. Aunque también pueden pertenecer a cualquier combinación de bits entre ellas. Dos de estas combinaciones tienen nombres específicos: none (ninguna) y all (todas). Los valores particulares asignados a estas constantes dependen de la implementación. A título de ejemplo mostramos un conjunto de valores posibles:

// Nombre Valor    Patrón de bits
collate  = 1;      // 00000001
ctype    = 2;      // 00000010
monetary = 4;      // 00000100
numeric  = 8;      // 00001000
time     = 16;     // 00010000
messages = 32;     // 00100000
Aparte de las dos combinaciones con nombre propio:
none     = 0;      // 00000000
all      = 63      // 00111111

Puede existir cualquier otro tipo que sea combinación de los anteriores y que se identificaría por su valor. Por ejemplo, el valor 12 correspondería al tipo numeric-monetary, y el valor 9 al tipo collate-numeric-monetary. Observe que el tipo all puede definirse como:

all = (collate | ctype | monetary | numeric | time | message );

Las facetas estándar

A continuación se incluye una breve descripción de las categorías básicas. Observe que en realidad las facet estándar son clases genéricas. En la descripción que sigue, una expresión como num_get<charT,InputIterator> significa que la faceta num_get es una plantilla que acepta dos argumentos: un tipo carácter (charT) y un iterador de entrada. Observe que muchas de las facetas estándar están desdobladas en dos clases que aceptan respectivamente iteradores de entrada y de salida, según el tipo de operación que soportan.

Categoría Facetas incluidas
numeric numpunct<char>

num_get<char> num_put<char>

numpunct<wchar_t>

num_get<wchar_t> num_put<wchar_t>

time time_get<char>

time_put<char>

time_get<wchar_t>

time_put<wchar_t>

monetary moneypunct<char>

moneypunct<char,true>

money_get<char>

money_put<char>

moneypunct<wchar_t>

moneypunct<wchar_t,true>

money_get<wchar_t>

money_put<wchar_t>

ctype ctype<char>

codecvt<char,char,mbstate_t>

ctype<wchar_t>

codecvt<wchar_t,char,mbstate_t>

collate collate<char> collate<wchar_t>
messages messages<char> messages<wchar_t>

Numeric

Las facetas num_get<charT, InputIterator> y num_put<charT, OutputIterator> manejan el formateo numérico. Estas clases disponen de métodos get() y put() en versiones para los tipos long, double, etc. La faceta numpunct<charT> especifica la puntuación de los formatos numéricos. Para ello dispone de métodos como decimal_point(), thousands_sep(), etc.

Time

Las clases time_get<charT, InputIterator> y time_put<charT, OutputIterator> manejan los localismos relativos a fecha y hora. Disponen de métodos como get_time(), get_date(), get_weekday(), etc.

Monetary

Las clases money_get<charT, InputIterator> y money_put<charT, OutputIterator> manejan los localismos monetarios. Disponen de métodos get() y put() cuya finalidad es respectivamente analizar o generar una secuencia de dígitos representando una cantidad en fracción monetaria más pequeña la moneda correspondiente. Por ejemplo: la secuencia $1,056.23 en un localismo estándar USA puede traducirse en el número 105623 (centavos de Dolar USA) o en la cadena de caracteres "105623".

La plantilla moneypunct<charT, bool> asume con las cantidades monetarias un papel análogo al de la clase numpunct<charT> con los formatos numéricos. Dispone de métodos como curr_symbol(), etc.

Ctype

La clase ctype<charT> encapsula las funcionalidades de clasificación de caracteres mediante métodos como tolower(), toupper(), isspace(), isprint(), etc. La faceta codecvt<internT, externT, stateT> permite la conversión entre distintos sistemas de codificación. Por ejemplo, del sistema JIS a Unicode. Sus métodos principales son in() y out(). Existe una especialización de esta plantilla codecvt<wchar_t, char, mbstate_t> que realiza conversiones de sistema multibyte a caracteres anchos.

Collate

La clase collate<charT> permite operaciones de ordenación y comparación de cadenas de caracteres, mediante métodos como compare(), hash() o transform().

Messages

La faceta messages<charT> implementa la especificación del consorcio X/Open para inclusión de mensajes en los programas (recordemos que la internacionalización aconseja mantener los mensajes fuera del cuerpo del ejecutable. Dispone de funciones del tipo open() y close() para mantener catálogos de mensajes. También para recuperarlos individualmente mediante funciones como get(..., int msgid,...).

Acceder a los locales

Una interesante característica de los locales es la forma en que se acceden sus facetas. Esto no se realiza como cabría esperar mediante un método de la clase locale, sino mediante un par de funciones externas (definidas en la cabecera <locale>), que aceptan un locale como argumento. Es posible determinar si un objeto determinado contiene una faceta mediante la función has_facet(). A su vez la función use_facet() devuelve una referencia a la faceta para que pueda ser utilizada.

Como la mayoría de entidades de la LE, ambas funciones (en realidad son funciones genéricas), están definidas en el subespacio std.

use_facet()

Prototipo

template <class Facet> const Facet& use_facet(const locale& loc);

Este método devuelve una referencia a la faceta Facet señalada en el argumento de la plantilla. La faceta se especifica incluyéndola explícitamente en el argumento de la plantilla (ver ejemplo). Si el tipo señalado por Facet no está presente en el objeto loc, (o en su defecto, en el locale gobal), la función lanza una excepción bad_cast en caso contrario devuelve una referencia a la faceta, que permanece válida mientras exista una copia del locale loc utilizado. Ejemplo (sin incluir ningún dispositivo de control de las posibles excepciones):

#include <locale>
#include <iostream> using namespace std;
 
int main () {       // ==========
   locale loc;
   const ctype<char>& ct = use_facet<ctype<char> >(loc); // M2:
   cout << 'a' << ct.toupper('c') << endl;     // -> aC
   return 0;
}

En este caso se construye una referencia ct a la faceta ctype para los tipos char y se inicia con el valor devuelto por la función use_facet. A continuación se utiliza el método toupper() del objeto ct para transformar un carácter minúscula a mayúscula.

Observe el espacio entre los símbolos >> de la sentencia M2, que es necesario para que el compilador pueda distinguirlos del operador >>. Esta invocación de la función genérica use_facet utiliza la sintaxis que hemos denominado instanciación implícita específica.

De los tres compiladores probados: Borland C++ 5.5; MS Visual C++ 6.0 y GNU cpp 2.95.2, solo el de Borland compila el ejemplo sin problemas. El manual Borland señala que si el compilador no soporta este tipo de instanciación específica (una característica relativamente nueva del lenguaje que no está totalmente implementada en muchos compiladores), es preciso utilizar una sintaxis alternativa, correspondiente a una versión sobrecargada de la anterior que si puede ser soportada por el compilador:

template <class Facet> const Facet& use_facet(const locale& loc, Facet* pf);

En este supuesto, la sentencia M2 del ejemplo quedaría como sigue:

const ctype<char>& ct = use_facet(loc,(ctype<char>*)0);

Obsérvese que como segundo argumento se pasa un puntero nulo (valor 0) al que se ha aplicado un modelado para adaptarlo al tipo esperado por esta nueva versión de use_facet.

has_facet()

Prototipo:

template <class Facet> bool has_facet(const locale&) throw();

Esta función permite establecer si un locale tiene un tipo determinado de faceta. Devuelve cierto (true) en caso afirmativo, y falso (flase) en caso contrario. Como en el caso anterior, la instanciación debe realizarse con indicación explícita del tipo a utilizar por la plantilla. Ejemplo:

#include <locale>
...
using namespace std; 
cout << ((has_facet<ctype<char> >(L1)) ? "Si" : "NO") << endl; // -> Si

Véase también

Fuente