Notas de estudio de C++11 (4) - Herramientas generales (Parte 2)

Es demasiado largo, vamos a escribirlo en dos partes,
el libro continuará.

4. Extremos numéricos

std::numeric_limits es una clase de plantilla definida en la biblioteca estándar de C++, ubicada en un archivo de encabezado. Proporciona información sobre propiedades y valores extremos de varios tipos numéricos. Esta información puede ayudarnos a comprender el rango numérico, la precisión y otras características relacionadas con números de un tipo específico cuando realizamos procesamiento numérico en el programa.

Precisión mínima

tipo longitud mínima
carbonizarse 1 byte
corto 2 bytes
En t 2 bytes
largo tiempo 4 bytes
mucho tiempo 8 bytes
flotar 4 bytes
doble 8 bytes
largo doble 8 bytes

Límites_numéricos genéricos

template<typename T>
class numeric_limits {
    
    
public:
    static constexpr bool is_specialized = false;

    static constexpr T min() noexcept {
    
    
        return T();
    }

    static constexpr T max() noexcept {
    
    
        return T();
    }

    // 其他成员函数和常量...
};

Las plantillas genéricas proporcionan valores límite predeterminados, lo que significa que al usar la plantilla genérica de std::numeric_limits, proporcionará un conjunto predeterminado de valores límite si no se realiza una especialización para un tipo en particular.

Para tipos de datos básicos (como enteros, números de punto flotante, etc.), la plantilla general proporcionará valores extremos predeterminados adecuados según las características del tipo. Por ejemplo, para el tipo entero con signo int, std::numeric_limits::min() devuelve el valor mínimo del tipo y std::numeric_limits::max() devuelve el valor máximo del tipo.

Para los tipos de coma flotante, std::numeric_limits::min() devuelve el valor positivo más pequeño de ese tipo y std::numeric_limits::max() devuelve el valor finito más grande de ese tipo.

La plantilla genérica también proporciona otra información extrema predeterminada, como precisión, error de redondeo, etc. Estos extremos predeterminados se definen en función de las características generales del tipo y las especificaciones estándar.

#include <iostream>
#include <limits>

int main() {
    
    
    std::cout << "int 类型的最小值:" << std::numeric_limits<int>::min() << std::endl;
    std::cout << "int 类型的最大值:" << std::numeric_limits<int>::max() << std::endl;
    std::cout << "float 类型的最小精度:" << std::numeric_limits<float>::epsilon() << std::endl;
    std::cout << "double 类型的正无穷大:" << std::numeric_limits<double>::infinity() << std::endl;
    std::cout << "double 类型的静默非数值(NaN):" << std::numeric_limits<double>::quiet_NaN() << std::endl;
    std::cout << "double 类型的位数:" << std::numeric_limits<double>::digits << std::endl;

    return 0;
}

limites_numéricos especializados

Para determinados tipos de datos, como tipos de clase definidos por el usuario o tipos numéricos especiales, es posible que estos valores predeterminados no se apliquen porque estos tipos pueden tener diferentes rangos numéricos o un comportamiento especial. Para atender estos casos especiales, está disponible una especialización de std::numeric_limits.

La especialización se logra proporcionando una versión especializada de una plantilla para un tipo particular, para anular las propiedades predeterminadas y los extremos. Al especializarnos en std::numeric_limits, podemos proporcionar valores límite personalizados e información de atributos para tipos específicos.

El siguiente es un ejemplo que muestra cómo especializar std::numeric_limits para proporcionar valores límite personalizados e información de atributos para un tipo personalizado MyType:

#include <iostream>
#include <limits>

class MyType {
    
    
    // 自定义类型的定义和实现
};

namespace std {
    
    
    template <>
    class numeric_limits<MyType> {
    
    
    public:
    	static constexpr bool is_specialized = true;
        static constexpr MyType min() {
    
     return MyType{
    
    }; }  // 自定义的最小值
        static constexpr MyType max() {
    
     return MyType{
    
    }; }  // 自定义的最大值
    };
}

int main() {
    
    
    std::cout << "MyType 类型的最小值:" << std::numeric_limits<MyType>::min() << std::endl;
    std::cout << "MyType 类型的最大值:" << std::numeric_limits<MyType>::max() << std::endl;

    return 0;
}

En el ejemplo anterior, proporcionamos valores mínimos y máximos personalizados para el tipo personalizado MyType al definir una especialización de std::numeric_limits en el espacio de nombres estándar. A través de la especialización, podemos proporcionar información extrema personalizada y de propiedad para cualquier tipo según sea necesario.

Cabe señalar que la especialización de std::numeric_limits es un uso avanzado, que generalmente se usa cuando se trata de tipos personalizados o necesidades especiales. Para la mayoría de los tipos de datos básicos, el std::numeric_limits predeterminado suele ser suficiente.

Reponer

Los límites numéricos generales y las versiones especializadas se colocan en el archivo de encabezado <limite>, y las versiones especializadas cubren todos los tipos básicos numéricos.
Las constantes C originales se definen en <climits>,<limits.h>,<cfloat>,<float.h>
inserte la descripción de la imagen aquíinserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

5. Tipo rasgo

Los rasgos de tipo (Type Traits) son un conjunto de clases de plantilla en C++ para obtener y manipular información de tipo en tiempo de compilación. Proporcionan una forma de realizar la verificación y manipulación de tipos en el momento de la compilación, lo que permite que el compilador realice operaciones como la compilación condicional, la conversión de tipos y la especialización de plantillas en función de las propiedades de los tipos.

Sobrecarga elástica para tipos enteros

Suponiendo que hay una función que puede pasar parámetros reales enteros y de punto flotante, generalmente es necesario escribir varias funciones sobrecargadas, incluidas short, int, float, double, etc., lo que no solo es engorroso sino que también necesita agregar nuevos tipos, y Type trait puede simplificarlo.

#include <iostream>
#include <type_traits>

// 重载版本1:针对整数类型
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
process(T value) {
    
    
    std::cout << "整数值:" << value << std::endl;
}

// 重载版本2:针对非整数类型
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type
process(T value) {
    
    
    std::cout << "非整数值:" << value << std::endl;
}

int main() {
    
    
    process(10);        // 调用重载版本1,传入整数类型
    process(3.14);      // 调用重载版本2,传入非整数类型

    return 0;
}

De esta manera, solo se requieren dos implementaciones para contener múltiples tipos de parámetros.

Manejar tipos comunes

Tipo común se refiere al tipo común más bajo en un grupo de tipos que pueden operar y devolver un tipo consistente. En C++, puede usar la plantilla de rasgos de tipo std::common_type para obtener el tipo común más bajo de un conjunto de tipos.

Aquí hay un código de muestra que demuestra cómo usar std::common_type para manejar tipos comunes:

#include <iostream>
#include <type_traits>

template <typename T1, typename T2>
void process(T1 value1, T2 value2) {
    
    
    using CommonType = typename std::common_type<T1, T2>::type;
    CommonType result = value1 + value2;
    std::cout << "结果:" << result << std::endl;
}

int main() {
    
    
    process(10, 3.14);      // 传入整数和浮点数
    process(5.5, 2.7);      // 传入两个浮点数
    process(7, 8);          // 传入两个整数

    return 0;
}

En el ejemplo anterior, definimos una plantilla de función de proceso que acepta dos parámetros valor1 y valor2 y usa std::common_type para obtener el tipo común más bajo CommonType de estos dos parámetros. Luego, usamos CommonType para declarar un resultado variable, agregamos valor1 y valor2 y asignamos el resultado a resultado. Finalmente, enviamos el resultado a la consola.

En la función principal, llamamos a la función de proceso para pasar diferentes tipos de parámetros, incluidos números enteros y de punto flotante. std::common_type deducirá automáticamente el tipo común más bajo y realizará la conversión de tipo correspondiente y la operación en el resultado.

Al usar std::common_type, podemos procesar un conjunto de parámetros con diferentes tipos y obtener su tipo común más bajo, realizando así el procesamiento de tipos comunes. Esto es útil en la programación genérica y la metaprogramación de plantillas para manejar operaciones en varios tipos de combinaciones.

otras operaciones

para todos los tipos

inserte la descripción de la imagen aquí

para clase clase

inserte la descripción de la imagen aquí

Tenga en cuenta que bool y todos los caracteres se tratan como clases enteras

Relación de tipos de verificación

inserte la descripción de la imagen aquí

cambio de tipo

inserte la descripción de la imagen aquí

otro

inserte la descripción de la imagen aquí

envoltorio de referencia

std::reference_wrapper es una plantilla de clase en la biblioteca estándar de C++, ubicada en un archivo de encabezado. Se utiliza para envolver tipos de referencia, proporcionando una semántica de referencia ligera, lo que permite que los objetos se pasen y manipulen por referencia.

La función principal de std::reference_wrapper es encapsular el tipo de referencia en un objeto, para que tenga semántica de objeto. Esto facilita el paso de referencias como argumentos de función, almacenarlos en contenedores o usarlos en otras situaciones donde se requieren objetos, sin introducir semántica de puntero adicional ni administración de memoria.

El uso de std::reference_wrapper puede lograr las siguientes funciones:

  • Pasar referencias como parámetros de función: puede pasar referencias como parámetros de función sin utilizar punteros ni copiar objetos.
  • Almacenamiento de tipos de referencia: los tipos de referencia se pueden almacenar en contenedores, como std::vector<std::reference_wrapper>.
  • Uso de referencias en algoritmos: puede usar tipos de referencia en algoritmos de biblioteca estándar sin usar punteros ni copiar objetos.

A continuación se muestra un código de ejemplo que demuestra cómo utilizar

#include <iostream>
#include <functional>

void increment(int& value) {
    
    
    ++value;
}

int main() {
    
    
    int num = 10;
    std::reference_wrapper<int> ref(num);

    increment(ref);

    std::cout << "num: " << num << std::endl;

    return 0;
}

En el ejemplo anterior, definimos una función de incremento que toma un parámetro de referencia y lo incrementa. En la función principal, creamos un objeto std::reference_wrapper ref y le pasamos la referencia de num. Luego, llamamos a la función de incremento y pasamos ref, en realidad una referencia a num. Finalmente, imprimimos el valor de num y vemos que se ha incrementado.

Al usar std::reference_wrapper, podemos pasar y manipular tipos de referencia como objetos, proporcionando una semántica de referencia más conveniente y flexible. A menudo se usa en escenarios como programación genérica, objetos de función, algoritmos STL, etc.

Envoltorio de tipo de función

std::function es una plantilla de clase proporcionada en la biblioteca estándar de C++, que se usa para encapsular diferentes tipos de objetos a los que se puede llamar y proporcionar una interfaz de llamada coherente.

La plantilla de clase para std::function se define de la siguiente manera:

template<class R, class... Args>
class function<R(Args...)>;

donde R es el tipo de retorno y Args... es la lista de tipos de argumentos.

Al usar std::function, puede crear un objeto de función que puede envolver diferentes tipos de entidades a las que se puede llamar, como punteros de función, objetos de función, punteros de función miembro, expresiones lambda, etc.

std::function proporciona la siguiente funcionalidad y uso principales:

  • Encapsulación de objetos a los que se puede llamar: std::function se puede utilizar para encapsular varios objetos a los que se puede llamar en un objeto de función unificado para que tengan la misma interfaz de llamada.
  • Almacenar y pasar objetos invocables: los objetos std::function se pueden copiar, almacenar y pasar como objetos ordinarios. Esto lo hace ideal para pasar objetos invocables como argumentos a funciones, almacenados en contenedores o como variables miembro de clase.
  • Llamada polimórfica: a través de std::function, se pueden llamar diferentes tipos de objetos llamables de forma unificada, sin importar sus tipos específicos. Esto hace que el código sea más flexible y extensible.

Aquí hay un ejemplo que muestra cómo usar std::function:

#include <iostream>
#include <functional>

int add(int a, int b) {
    
    
    return a + b;
}

class Foo {
    
    
public:
    int multiply(int a, int b) {
    
    
        return a * b;
    }
};

int main() {
    
    
    std::function<int(int, int)> func;

    func = add;
    int result1 = func(3, 4);
    std::cout << "Result1: " << result1 << std::endl;

    Foo foo;
    func = std::bind(&Foo::multiply, &foo, std::placeholders::_1, std::placeholders::_2);
    int result2 = func(3, 4);
    std::cout << "Result2: " << result2 << std::endl;

    return 0;
}

En el ejemplo anterior, primero definimos una función de suma y una clase Foo, donde la clase Foo tiene una función miembro multiplicar. Luego, declaramos un objeto std::function func cuyo tipo de función es int(int, int).

Primero asignamos la función de agregar a func, luego usamos func para llamar a la función de agregar y mostrar el resultado. A continuación, vinculamos la función miembro multiplicar de la clase Foo a func usando std::bind, pasando un puntero de objeto de la clase Foo y dos marcadores de posición como parámetros. Finalmente, llamamos a Foo::multiply con func y mostramos el resultado.


Los marcadores de posición son objetos especiales en la biblioteca estándar de C++ que ocupan las posiciones de los parámetros de los objetos de función. En el objeto de función, el marcador de posición indica que el parámetro en esta posición se reemplazará con el valor correspondiente cuando se llame realmente.

En el uso de std::bind, los marcadores de posición std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 y más marcadores de posición que aumentan sucesivamente _4, _5, etc. se utilizan para identificar las posiciones de los parámetros del objeto de función. Con marcadores de posición, podemos especificar la posición del parámetro al vincular la función sin proporcionar el valor real del parámetro.

En el código de muestra, usamos dos marcadores de posición std::placeholders::_1 y std::placeholders::_2:

func = std::bind(&Foo::multiply, &foo, std::placeholders::_1, std::placeholders::_2);

Aquí, vinculamos la función de miembro Foo::multiply a func y usamos dos marcadores de posición para especificar la posición de los parámetros. Esto significa que cuando llamamos a func, los argumentos se pasarán en lugar de los marcadores de posición.

Cuando se llama a func(3, 4), el marcador de posición std::placeholders::_1 corresponde al primer parámetro, que es 3, y el marcador de posición std::placeholders::_2 corresponde al segundo parámetro, que es 4. Por lo tanto, los parámetros 3 y 4 se pasarán a la función miembro Foo::multiply como parámetros reales.

El uso de marcadores de posición puede hacer que los objetos de función sean más flexibles, especialmente en términos de vinculación de objetos de función y asignación de posición de parámetros. Nos permite diferir el paso de parámetros y proporcionar valores de parámetros de forma dinámica al llamar al objeto de función.

Cabe señalar que el número y la posición de los marcadores de posición deben coincidir con el número y la posición de los parámetros del objeto de función. De lo contrario, dará lugar a errores de compilación o paso de parámetros incorrectos.

En el ejemplo, los marcadores de posición se utilizan para asociar el objeto de función enlazado con el objeto foo y las posiciones de los parámetros. De esta manera, cuando llamamos al objeto de función enlazada, llama a la función multiplicar en el objeto foo, pasando los argumentos posicionales correspondientes a la función.


A través de std::function, podemos encapsular diferentes tipos de objetos invocables en un objeto unificado y llamarlos de manera unificada. Esto proporciona mayor flexibilidad y generalidad, haciendo que el uso de objetos de función sea más conveniente y extensible.

6. Funciones auxiliares

máximo y mínimo

Todas las funciones minmax() y todas las funciones con columnas de valor inicial comienzan desde c ++ 11.
inserte la descripción de la imagen aquíCuando usamos funciones en archivos de encabezado, generalmente necesitamos especificar funciones de comparación (o predicados) para determinar el orden de los elementos o cumplir otras condiciones. Una función de comparación es un objeto invocable que toma dos argumentos y devuelve un valor booleano que compara el orden de dos elementos.

comparación personalizada

Aquí hay un ejemplo de clasificación usando funciones de comparación:


#include <algorithm>
#include <vector>
#include <iostream>

bool cmp(int a, int b) {
    
    
    // 按照绝对值大小进行比较
    return std::abs(a) < std::abs(b);
}

int main() {
    
    
    std::vector<int> nums = {
    
    -3, 2, -1, 4, -5};
    std::sort(nums.begin(), nums.end(), cmp);

    for (const auto& num : nums) {
    
    
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

En el ejemplo anterior, definimos una función de comparación cmp, que compara elementos según su valor absoluto. Luego ordenamos el contenedor nums usando la función std::sort, pasando la función cmp como una función de comparación.

Los resultados de clasificación se ordenarán según el valor absoluto de los elementos de menor a mayor, y los resultados de salida son: -1, 2, -3, 4, -5.

Al personalizar la función de comparación, podemos ordenar o comparar elementos según condiciones específicas. Esto es útil en muchos algoritmos y operaciones, como órdenes de clasificación personalizadas, elementos de filtrado por reglas específicas y más. De acuerdo con las diferentes necesidades, podemos escribir diferentes funciones de comparación para cumplir con una lógica de clasificación o comparación específica.

intercambiar dos valores

std::swap es una función de intercambio general en la biblioteca estándar de C++, ubicada en el archivo de encabezado.

La función std::swap tiene varias versiones sobrecargadas para intercambiar objetos de diferentes tipos. Su plantilla genérica se define de la siguiente manera:

namespace std {
    
    
    template <class T>
    void swap(T& a, T& b);
}

donde T es el tipo de objeto a intercambiar y a y b son referencias a los objetos a intercambiar.

Al llamar a std::swap(a, b), según el tipo de objeto real, el compilador elegirá la versión sobrecargada adecuada para realizar la operación de intercambio. std::swap ya tiene definiciones de especialización predeterminadas para tipos integrados y tipos proporcionados por la biblioteca estándar.

Además, para un tipo personalizado, podemos realizar la operación de intercambio del tipo personalizado definiendo una versión especializada del tipo o proporcionando una función de intercambio personalizada. Por ejemplo:

namespace std {
    
    
    template <>
    void swap<MyType>(MyType& a, MyType& b) {
    
    
        // 自定义类型的交换操作
    }
}

Al proporcionar una especialización del tipo personalizado MyType en el espacio de nombres estándar, podemos sobrecargar la función std::swap para realizar una operación de intercambio específica al intercambiar objetos del tipo personalizado.

El siguiente es un ejemplo de intercambio de valor usando std::swap:

#include <algorithm>
#include <iostream>

int main() {
    
    
    int a = 10;
    int b = 20;

    std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;

    std::swap(a, b);

    std::cout << "After swap: a = " << a << ", b = " << b << std::endl;

    return 0;
}

En el ejemplo anterior, definimos dos variables enteras a y b e inicializamos a 10 y 20 respectivamente. Luego, intercambiamos los valores de a y b usando la función std::swap.

La salida es:

Before swap: a = 10, b = 20
After swap: a = 20, b = 10

Al usar std::swap, podemos intercambiar convenientemente los valores de dos objetos sin escribir explícitamente variables temporales o funciones de intercambio personalizadas. Esto es muy útil en muchas situaciones, como en algoritmos de clasificación, operaciones de contenedores, etc. donde se deben intercambiar valores. Desde c++11, la biblioteca estándar proporciona una versión sobrecargada para array . Además, para los tipos definidos por el usuario, las operaciones de intercambio definidas por el usuario se pueden implementar sobrecargando operator=.

En resumen, std::swap es una función de intercambio general proporcionada por la biblioteca estándar de C++, que se puede usar para intercambiar objetos de diferentes tipos. Ya existen definiciones de especialización predeterminadas para tipos integrados y tipos proporcionados por la biblioteca estándar. Para un tipo personalizado, podemos implementar la operación de intercambio del tipo personalizado a través de una versión especializada o una función de intercambio personalizada.

operador de comparación

En C++11, se pueden usar los siguientes operadores para comparar la relación de tamaño de dos objetos:

!=(不等于):用于检查两个对象是否不相等。
>(大于):用于检查一个对象是否大于另一个对象。
<(小于):用于检查一个对象是否小于另一个对象。
>=(大于等于):用于检查一个对象是否大于或等于另一个对象。
<=(小于等于):用于检查一个对象是否小于或等于另一个对象。

Estos operadores se pueden usar en tipos integrados (como números enteros, números de punto flotante, etc.) y tipos definidos por el usuario, siempre que se definan las sobrecargas de operadores correspondientes o que los objetos admitan las operaciones de comparación relevantes.

Aquí hay un ejemplo que muestra cómo usar estos operadores para comparar dos números enteros:

#include <iostream>

int main() {
    
    
    int a = 10;
    int b = 5;

    if (a != b) {
    
    
        std::cout << "a is not equal to b" << std::endl;
    }

    if (a > b) {
    
    
        std::cout << "a is greater than b" << std::endl;
    }

    if (a < b) {
    
    
        std::cout << "a is less than b" << std::endl;
    }

    if (a >= b) {
    
    
        std::cout << "a is greater than or equal to b" << std::endl;
    }

    if (a <= b) {
    
    
        std::cout << "a is less than or equal to b" << std::endl;
    }

    return 0;
}

La salida es:

a is not equal to b
a is greater than b
a is not less than b
a is greater than or equal to b
a is not less than or equal to b

En el ejemplo anterior, comparamos dos números enteros a y b, y generamos un mensaje correspondiente basado en su relación de magnitud. Tenga en cuenta que si desea comparar objetos de un tipo personalizado, debe sobrecargar el operador de comparación correspondiente.

7.Proporción de clase<>

std::ratio es una clase de plantilla en la biblioteca estándar de C++ para representar proporciones de números racionales. Está en el archivo de cabecera.

La clase de plantilla std::ratio se define de la siguiente manera:


template <intmax_t Num, intmax_t Denom = 1>
class ratio;

Entre ellos, Num representa el numerador, Denom representa el denominador y el valor predeterminado es 1. Tanto Num como Denom deben ser tipos enteros.

La clase de plantilla std::ratio proporciona una forma de representar proporciones de números racionales en tiempo de compilación, que se puede usar para realizar conversiones de unidades, calcular relaciones de proporciones y más. Su función principal es proporcionar un tipo estático en tiempo de compilación para representar relaciones proporcionales comunes sin necesidad de cálculos de tiempo de ejecución.

Aquí hay un ejemplo usando std::ratio:

#include <iostream>
#include <ratio>

int main() {
    
    
    using one_half = std::ratio<1, 2>;
    using one_third = std::ratio<1, 3>;
    using two_thirds = std::ratio_add<one_third, one_third>;

    std::cout << "1/2 = " << one_half::num << "/" << one_half::den << std::endl;
    std::cout << "1/3 = " << one_third::num << "/" << one_third::den << std::endl;
    std::cout << "1/3 + 1/3 = " << two_thirds::num << "/" << two_thirds::den << std::endl;

    return 0;
}

La salida es:

1/2 = 1/2
1/3 = 1/3
1/3 + 1/3 = 2/3

En este ejemplo, definimos tres alias para el tipo std::ratio: un medio para 1/2, un tercio para 1/3 y dos tercios para 1/3 + 1/3.

Al acceder a las variables miembro estáticas num y den de la clase std::ratio, podemos obtener el numerador y el denominador de la relación de números racionales y generarlos.

Expresión

inserte la descripción de la imagen aquí

unidades predefinidas

Los archivos de encabezado en la biblioteca estándar de C++ proporcionan algunas unidades std::ratio predefinidas, que se utilizan para representar relaciones proporcionales comunes.
inserte la descripción de la imagen aquí
Estas unidades predefinidas hacen que sea más conveniente expresar cantidades físicas y puede usarlas directamente para la conversión de unidades y los cálculos de proporciones. Por ejemplo, std::kilo representa mil, y puede multiplicar un valor por std::kilo para convertirlo en mil veces.

Cabe señalar que std::ratio es un tipo calculado en tiempo de compilación, su valor se determina en tiempo de compilación y no admite operaciones aritméticas en tiempo de ejecución. Se utiliza principalmente para la conversión de unidades y el cálculo de proporciones en tiempo de compilación, por ejemplo, tiene una amplia gama de aplicaciones en metaprogramación de plantillas y verificación de tipos estáticos.

8. Reloj y temporizador

Los archivos de encabezado se introdujeron en C++ 11 para proporcionar funciones relacionadas con el reloj y el temporizador para medir el tiempo e implementar temporizadores.

Duración (periodo de tiempo)

Los archivos de encabezado en C++11 presentan la plantilla de clase std::chrono::duration para representar intervalos de tiempo o duraciones. std::chrono::duration es una clase de cantidad de tiempo general que se puede usar para representar intervalos de tiempo en diferentes unidades, como segundos, milisegundos, microsegundos, etc.

El parámetro de plantilla de std::chrono::duration consta de dos partes: Rep y Period. Rep representa el tipo subyacente del intervalo de tiempo, generalmente un tipo aritmético (como int, double, etc.), y Period representa la unidad del intervalo de tiempo. El período es una instancia del tipo std::ratio, que se utiliza para representar la relación proporcional entre el numerador y el denominador, que determina la unidad del intervalo de tiempo.

Aquí hay un ejemplo usando std::chrono::duration:

#include <iostream>
#include <chrono>

int main() {
    
    
    // 定义一个持续时间为 5 秒的 duration
    std::chrono::duration<int> durationSeconds(5);

    // 定义一个持续时间为 2.5 秒的 duration
    std::chrono::duration<double> durationSecondsDouble(2.5);

    // 输出 duration 的数值和单位
    std::cout << "durationSeconds: " << durationSeconds.count() << " seconds" << std::endl;
    std::cout << "durationSecondsDouble: " << durationSecondsDouble.count() << " seconds" << std::endl;

    // 将 duration 转换为毫秒
    std::chrono::duration<int, std::milli> durationMilliseconds = std::chrono::duration_cast<std::chrono::duration<int, std::milli>>(durationSeconds);

    // 输出转换后的 duration 的数值和单位
    std::cout << "durationMilliseconds: " << durationMilliseconds.count() << " milliseconds" << std::endl;

    return 0;
}

En este ejemplo, creamos dos objetos std::chrono::duration de diferentes tipos: una duración de tipo entero con una duración de 5 segundos y una duración de tipo doble con una duración de 2,5 segundos. Usamos la función miembro count() para obtener el valor de la duración y usamos std::chrono::duration_cast para la conversión de unidades.

La salida es:

durationSeconds: 5 seconds
durationSecondsDouble: 2.5 seconds
durationMilliseconds: 5000 milliseconds

inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

Al usar std::chrono::duration, los intervalos de tiempo se pueden calcular, convertir y representar fácilmente sin administrar manualmente las conversiones entre diferentes unidades.

Reloj

El reloj es un punto de referencia para la medición del tiempo. C++11 proporciona tres tipos de relojes:

  • std::chrono::system_clock: utilizado para representar la hora actual del sistema.
  • std::chrono::steady_clock: se utiliza para representar una hora relativamente estable y no se verá afectado por la hora del sistema.
  • std::chrono::high_solution_clock: proporciona un reloj de alta precisión, que puede ser un alias para system_clock osteady_clock.

Estos relojes proporcionan la función miembro now() para obtener la hora del reloj actual.

Aquí hay un ejemplo usando std::chrono::steady_clock:

#include <iostream>
#include <chrono>

int main() {
    
    
    auto start = std::chrono::steady_clock::now();

    // 执行一些操作

    auto end = std::chrono::steady_clock::now();
    auto duration = end - start;

    std::cout << "耗时:" << std::chrono::duration<double>(duration).count() << " 秒" << std::endl;

    return 0;
}

En este ejemplo, usamos std::chrono::steady_clock para obtener los puntos de tiempo de inicio y fin, y calculamos la diferencia de tiempo entre ellos para obtener el tiempo de ejecución del programa.
inserte la descripción de la imagen aquí

Temporizador

C ++ 11 no proporciona directamente una clase de biblioteca estándar para temporizadores, pero puede usar Clock y algunas otras funciones para implementar funciones de temporizador. Por ejemplo, puede usar la función std::this_thread::sleep_for() para dejar que el subproceso duerma durante un período de tiempo para implementar una función de temporizador simple.

Aquí hay un ejemplo de implementación de un temporizador usando std::this_thread::sleep_for():

#include <iostream>
#include <chrono>
#include <thread>

int main() {
    
    
    int count = 0;
    int target = 5;

    while (count < target) {
    
    
        std::this_thread::sleep_for(std::chrono::seconds(1));
        count++;
        std::cout << "定时器触发:" << count << std::endl;
    }

    std::cout << "定时器结束" << std::endl;

    return 0;
}

En este ejemplo, usamos la función std::this_thread::sleep_for() para hacer que el programa duerma durante 1 segundo y mostrar la cantidad de veces que se activa el temporizador. El programa finaliza el temporizador cuando el conteo alcanza el valor objetivo.

Es importante tener en cuenta que la implementación de los temporizadores puede variar entre los sistemas operativos y los compiladores. El ejemplo anterior solo proporciona un método de implementación simple, y es posible que se requieran funciones de temporizador más complejas en las aplicaciones reales, que se pueden expandir y optimizar de acuerdo con los requisitos específicos.
inserte la descripción de la imagen aquí

función en C

Las definiciones originalmente en <time.h> ahora se incluyen en <ctime>
inserte la descripción de la imagen aquí

Conversión entre punto de tiempo y hora del calendario

En el archivo de encabezado de C++11, la plantilla de clase std::chrono::time_point se puede usar para representar el punto de tiempo (Time Point). Un punto en el tiempo es un concepto abstracto de un momento específico, correspondiente al Tiempo del Calendario.

Para convertir entre un punto en el tiempo y una hora del calendario, se pueden usar las siguientes funciones y tipos:

  • std::chrono::system_clock: std::chrono::system_clock es un tipo de reloj usado para representar la hora actual del sistema. Se puede utilizar para obtener la hora actual del calendario.

  • std::chrono::time_point: std::chrono::time_point es una plantilla de clase que representa un punto en el tiempo. Se puede usar para almacenar y manipular valores en puntos en el tiempo.

  • std::chrono::duration: std::chrono::duration es una plantilla de clase que representa un intervalo de tiempo. Esto se puede utilizar para calcular la diferencia entre los puntos de tiempo.

Aquí hay un ejemplo de conversión entre un punto en el tiempo y una hora del calendario:

#include <iostream>
#include <chrono>
#include <ctime>

int main() {
    
    
    // 获取当前的日历时间
    std::time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

    // 将日历时间转换为时间点
    std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::from_time_t(currentTime);

    // 将时间点转换为日历时间
    std::time_t convertedTime = std::chrono::system_clock::to_time_t(timePoint);

    // 输出转换后的日历时间
    std::cout << "Converted time: " << std::asctime(std::localtime(&convertedTime));

    return 0;
}

En este ejemplo, primero usamos std::chrono::system_clock::now() para obtener el punto de tiempo actual y luego usamos std::chrono::system_clock::to_time_t() para convertir el punto de tiempo a tiempo de calendario (tipo std::time_t). A continuación, convertimos la hora del calendario a un punto en el tiempo usando std::chrono::system_clock::from_time_t(). Finalmente, enviamos el tiempo de calendario convertido al flujo de salida estándar usando std::asctime().

Tenga en cuenta que el punto en el tiempo y el tiempo del calendario pueden variar en precisión y rango. Los puntos en el tiempo generalmente tienen mayor precisión y rango, mientras que los tiempos del calendario están limitados a la precisión y el rango del tipo std::time_t.

Usando la conversión entre punto de tiempo y tiempo de calendario, puede convertir y operar fácilmente entre diferentes representaciones de tiempo para satisfacer diferentes necesidades.

Los temporizadores se usan a menudo en los hilos, esta parte se describe en detalle en el capítulo del hilo más adelante.

9. Algunos archivos de encabezado importantes

<cstddef>

El archivo de encabezado <cstddef> define algunos tipos y funciones relacionadas con las operaciones de tamaño y puntero
inserte la descripción de la imagen aquí

<cstdlib>

El archivo de encabezado define algunas funciones de biblioteca comunes, como funciones de administración de memoria (como malloc y free), funciones de conversión de tipos (como atoi y atof), funciones de números aleatorios (como rand y srand) y otras funciones comunes.
inserte la descripción de la imagen aquí

<ccadena>

El archivo de encabezado <cstring> define algunas funciones y tipos relacionados con la manipulación de cadenas, como funciones de copia de cadenas (como strcpy y strncpy), funciones de concatenación de cadenas (como strcat y strncat), funciones de comparación de cadenas (como strcmp y strncmp) y otras funciones de procesamiento de cadenas.
inserte la descripción de la imagen aquí

ejemplo

#include <iostream>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>

int main() {
    
    
    // 使用 cstddef 定义的类型
    std::size_t size = 10;
    std::ptrdiff_t diff = 5;
    std::nullptr_t nullPtr = nullptr;

    // 使用 cstdlib 的库函数
    int randomNumber = std::rand();
    std::cout << "Random number: " << randomNumber << std::endl;

    // 使用 cstring 的字符串操作函数
    char str1[] = "Hello";
    char str2[10];
    std::strcpy(str2, str1);
    std::strcat(str2, " World");
    std::cout << "Concatenated string: " << str2 << std::endl;

    // 使用 string 类进行字符串操作
    std::string s1 = "Hello";
    std::string s2 = "World";
    std::string s3 = s1 + " " + s2;
    std::cout << "Concatenated string: " << s3 << std::endl;

    return 0;
}

Este ejemplo demuestra cómo usar archivos de encabezado, y para tipos primitivos, funciones de biblioteca y manipulación de cadenas. Tenga en cuenta que cuando se trabaja con cadenas en C++, se recomienda utilizar la clase std::string en lugar de las cadenas tradicionales de estilo C (representadas como matrices de caracteres) para funciones de manipulación de cadenas más seguras y convenientes.

  • final del capitulo cinco

Supongo que te gusta

Origin blog.csdn.net/qq_44616044/article/details/131223759
Recomendado
Clasificación