Quantcast
Channel: Planeta Código
Viewing all articles
Browse latest Browse all 2733

Header Files: Flags fuertemente tipadas

$
0
0

Introducción

En muchos sistemas es frecuente tener que saber si determinada característica, opción, componente, etc. está habilitado o no. Para ello se suelen usar flags (banderas), definidas como constantes o enumeraciones, y vectores de booleanos o std::bitset.

enumCompilationFlags{CompilationFlags_CrossCompilation,CompilationFlags_Debug,CompilationFlags_Count};std::bitset<CompilationFlags_Count>compilation_flags;compilation_flags.set(CompilationFlags_Debug,true);

El principal problema de estas soluciones es que se basan en convertir un identificador en un índice en el vector / bitset, lo que lleva a que no haya comprobación en tiempo de compilación de que la característica esté soportada. Por ejemplo, puede ocurrir un desbordamiento de buffer si el índice supera el tamaño máximo del contenedor, o un error de lógica si se consulta un flag no correspondiente a dicho conjunto (pero con el mismo valor numérico).

Propuesta

Una posible solución es definir las banderas como tipos booleanos fuertemente tipados y usarlos en una tupla. En este artículo extenderemos la sintaxis que propusimos en una entrega anterior (Argumentos expresivos 1):

classFlag{boolm_value;public:Flag()=default;explicitFlag(boolvalue)noexcept:m_value{value}{}operatorbool()const{returnm_value;}};#define FLAG(name) struct name : Flag { using Flag::Flag; }
FLAG(CrossCompilation);FLAG(Debug);usingCompilationFlags=std::tuple<CrossCompilation,Debug>;

Así, podemos aprovechar el método std::get basado en tipos para consultar el estado de la bandera:

CompilationFlagscomp_flags;std::get<CrossCompilation>(comp_flags)=CrossCompilation{true};// to set a valueautoconstcross_compilation=std::get<CrossCompilation>(comp_flags);// to get a value

Ahora bien, esta sintaxis puede ser mejorada en varios aspectos; veamos cuáles son.

Estado inicial de la bandera

Lo primero es que no todas las banderas estarán en un estado off al inicio, por lo que podemos modificar el tipo Flag para considerar este escenario y dotarlas de un estado inicial explícito:

template<booldefault_value>classFlag{boolm_value{default_value};public:Flag()=default;explicitFlag(boolvalue)noexcept:m_value{value}{}operatorbool()const{returnm_value;}};#define FLAG(name, value) struct name : Flag<value> { using Flag::Flag; }
FLAG(CrossCompilation,false);FLAG(Debug,true);

Encapsulamiento

Lo siguiente es dotar de una mejor interfaz a nuestra solución. Para ello definiremos una clase Flags que se hará cargo de dichas funciones. Veremos esta solución en conjunto con la siguiente mejora.

Inicialización selectiva

Aunque las banderas tengan un estado inicial, éste puede que no sea apropiado en algunos casos. Una solución podría ser tener un constructor que reciba todas las banderas, pero claramente no es la opción más limpia, especialmente si el conjunto es grande. En su lugar aprovecharemos el tipado fuerte de las banderas para poder definir un constructor más flexible.

template<typename...Types>classFlags{public:Flags()=default;template<typenameFlag,typename...Args>explicitFlags(Flagflag,Args&&...args):Flags{args...}{std::get<Flag>(m_flags)=flag;}template<typenameT>boolis_enabled()constnoexcept{returnstd::get<T>(m_flags);}template<typenameT>voidset_enabled(Tconst&state)noexcept{std::get<T>(m_flags)=state;}private:std::tuple<Types...>m_flags;};

Ejemplo de uso

usingCompilationFlags=Flags<CrossCompilation,Debug>;CompilationFlagsconstcompilation_flags{Debug{false}};autoconstis_debug=compilation_flags.is_enabled<Debug>();

El ejemplo completo puede conseguirse acá.

Conclusión

Como se ha podido ver, el uso de tipos fuertemente tipados aumenta la expresividad del código, permiten soluciones máx flexibles y robustaz, y da una mayor cercanía entre la sintaxis y la semántica.

Por otro lado, permiten sacar partido a una de mis características favoritas de C++: el compilador. Si algo se puede hacer en tiempo de compilación, ¿por qué hacerlo en tiempo de ejecución? Si un fallo se puede detectar cuando sólo nosotros (los desarrolladores) somos los afectados, ¿por qué dejar que el cliente sea el que lo descubra? De todo esto hablaremos en una entrega futura, mientras tanto, y como diría Sheldon Cooper: ¡diversión con banderas!


Viewing all articles
Browse latest Browse all 2733

Latest Images

Trending Articles


Vimeo 10.7.1 by Vimeo.com, Inc.


Sapos para colorear


Letting Go Quotes


Love Song lyrics that marks your Heart


RE: Mutton Pies (frankie241)


Hato lada ym dei namar ka jingpyrshah jong U JJM Nichols Roy (Bah Joy) ngin...


Vimeo 10.7.0 by Vimeo.com, Inc.


Doodle Jump 3.11.34 by Lima Sky LLC


UPDATE SC IDOL: TWO BECOME ONE


KASAMBAHAY BILL IN THE HOUSE


Long Distance Relationship Tagalog Love Quotes


Presence Quotes – Positive Quotes


Love with Heart Breaking Quotes


FORECLOSURE OF REAL ESTATE MORTGAGE


Ka longiing longsem kaba skhem bad kaba khlain ka pynlong kein ia ka...


Vimeo Create - Video Maker & Editor 1.5.2 by Vimeo Inc


Vimeo 11.6.0 by Vimeo.com, Inc.


Re:Mutton Pies (lleechef)


FORTUITOUS EVENT


Pokemon para colorear



Latest Images