La biblioteca de rasgos de tipo:Corrección

La biblioteca de rasgos de tipo:Corrección

Los dos objetivos principales de la biblioteca de rasgos de tipo son muy convincentes:corrección y optimización. Hoy escribo sobre la corrección.

La biblioteca de rasgos de tipo le permite escribir consultas, comparar tipos y modificar tipos en tiempo de compilación. En mi publicación anterior sobre la biblioteca de características de tipos, solo escribí sobre consultas de tipos y comparación de tipos. Antes de escribir sobre el aspecto de corrección de la biblioteca de rasgos tipográficos, quiero escribir algunas palabras sobre las modificaciones tipográficas.

Modificaciones de tipo

La biblioteca de rasgos de tipo ofrece muchas metafunciones para manipular tipos. Aquí están los más interesantes.

// const-volatile modifications:
remove_const;
remove_volatile;
remove_cv;
add_const;
add_volatile;
add_cv;

// reference modifications:
remove_reference;
add_lvalue_reference;
add_rvalue_reference;

// sign modifications:
make_signed;
make_unsigned;

// pointer modifications:
remove_pointer;
add_pointer;

// other transformations:
decay;
enable_if;
conditional;
common_type;
underlying_type;

Para obtener un int de un int o un const int , tienes que preguntar por el tipo con ::type .

std::is_same<int, std::remove_const<int>::type>::value; // true
std::is_same<int, std::remove_const<const int>::type>::value; // true

Desde C++14, solo puede usar _t para obtener el tipo como con std::remove_const_t :

std::is_same<int, std::remove_const_t<int>>::value; // true
std::is_same<int, std::remove_const_t<const int>>::value; // true

Para tener una idea de cuán útiles son estas metafunciones de la biblioteca de rasgos de tipo, aquí hay algunos ejemplos.

  • std::decay : std::thread aplica std::decay a sus argumentos. Los argumentos de std::thread incluyendo la función ejecutada f y sus argumentos args . Decay significa que se realizan conversiones implícitas de matriz a puntero, de función a puntero y const/volatile se eliminan los calificadores y las referencias.
  • std::enable_if es una manera conveniente de usar SFINAE. SFINAE significa el fallo de sustitución no es un error y se aplica durante la resolución de sobrecarga de una plantilla de función. Significa que si falla la sustitución del parámetro de plantilla, la especialización se descarta del conjunto de sobrecarga, pero esta falla no provoca ningún error de compilación.
  • std::conditional es el operador ternario en tiempo de compilación.
  • std::common_type determina el tipo común entre todos los tipos al que se pueden convertir todos los tipos.
  • std::underlying_type determina el tipo de una enumeración.

Tal vez no esté convencido del beneficio de la biblioteca de rasgos de tipo. Permítanme terminar mi serie de publicaciones sobre la biblioteca de rasgos tipográficos con sus dos objetivos principales:corrección y optimización.

Corrección

Corrección significa que puede usar la biblioteca de rasgos de tipo en C++ 11 para hacer que su algoritmo sea más seguro. La siguiente implementación del algoritmo gcd requiere que el operador de módulo binario sea válido para sus argumentos.

// gcd2.cpp

#include <iostream>
#include <type_traits>

template<typename T>
T gcd(T a, T b) {
 static_assert(std::is_integral<T>::value, "T should be an integral type!"); // (1)
 if( b == 0 ){ return a; }
 else{
 return gcd(b, a % b);
 }
}

int main() {

 std::cout << gcd(100, 33) << '\n';
 std::cout << gcd(3.5,4.0) << '\n';
 std::cout << gcd("100","10") << '\n';

}

El mensaje de error es bastante explícito.

El compilador se queja inmediatamente de que un double o un const cha r* no es un tipo de datos integral. En consecuencia, el static_assert expresión en (1) despedido

Pero la corrección significa que puede usar las bibliotecas de rasgos de tipo para implementar conceptos como Integral , SignedIntegral y UnsignedIntegral en C++20.

template <typename T>
concept Integral = std::is_integral<T>::value; // (1)

template <typename T>
concept SignedIntegral = Integral<T> && std::is_signed<T>::value; // (2)

template <typename T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

El concepto Integral usa directamente las funciones type-traits std::is_integral (1) y el concepto SignedIntegral la función de rasgos de tipo std::is_signed (2).

Probémoslo y usemos el concepto Integral directamente.

// gcdIntegral.cpp

#include <iostream>
#include <type_traits>

template <typename T>
concept Integral = std::is_integral<T>::value;

template <typename T>
concept SignedIntegral = Integral<T> && std::is_signed<T>::value;

template <typename T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

Integral auto gcd(Integral auto a, decltype(a) b) {
 if( b == 0 ){ return a; }
 else{
 return gcd(b, a % b);
 }
}

int main() {

 std::cout << gcd(100, 33) << '\n';
 std::cout << gcd(3.5,4.0) << '\n';
 std::cout << gcd("100","10") << '\n';

}

Ahora, el algoritmo gcd es más fácil de leer. Requiere que el primer argumento a y su tipo de retorno son tipos de datos integrales. Para asegurar que el segundo argumento b tiene el mismo tipo como el primer tipo a , especifiqué su tipo como decltype(a) . En consecuencia, esta implementación del gcd algoritmo y el anterior en gcd2.cp p son equivalentes.

Ahora, el mensaje de error es más detallado como el anterior.

El mensaje de error del GCC no solo es demasiado detallado, sino que también es demasiado difícil de leer. Déjame probar Clang en Compiler Explorer. El mensaje de error sobre el uso erróneo de lecturas dobles como prosa:

Honestamente, no creo que un mensaje de error pueda ser más fácil de leer.

Finalmente, quería probar el último compilador de Microsoft Visual Studio. Este compilador admite conceptos con una excepción:la llamada sintaxis de plantilla de función abreviada. Puede que ya lo adivines. Usé la sintaxis de plantilla de función abreviada en mi algoritmo gcd. Puede leer más sobre esta agradable sintaxis en mi publicación anterior:C++20:Conceptos - Azúcar sintáctico.

¿Qué sigue?

Por supuesto, ya sabes sobre lo que voy a escribir en mi próxima publicación:la historia del rendimiento de la biblioteca de rasgos tipográficos.