C++11-Studiennotizen (4) – Allgemeine Tools (Teil 2)

Es ist zu lang, schreiben wir es in zwei Teilen,
das Buch wird weitergehen

4. Numerische Extreme

std::numeric_limits ist eine in der C++-Standardbibliothek definierte Vorlagenklasse, die sich in einer Header-Datei befindet. Es liefert Informationen über Eigenschaften und Extremwerte verschiedener numerischer Typen. Diese Informationen können uns helfen, den numerischen Bereich, die Genauigkeit und andere numerische Eigenschaften eines bestimmten Typs zu verstehen, wenn wir numerische Verarbeitungen im Programm durchführen.

Minimale Präzision

Typ minimale Länge
verkohlen 1 Byte
kurze Int 2 Bytes
int 2 Bytes
lange int 4 Bytes
lang lang int 8 Byte
schweben 4 Bytes
doppelt 8 Byte
langes Doppel 8 Byte

Generische numerische_Limits

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();
    }

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

Generische Vorlagen stellen Standardgrenzwerte bereit. Das bedeutet, dass bei Verwendung der generischen Vorlage std::numeric_limits ein Standardsatz von Grenzwerten bereitgestellt wird, wenn keine Spezialisierung für einen bestimmten Typ vorgenommen wird.

Für grundlegende Datentypen (z. B. Ganzzahlen, Gleitkommazahlen usw.) stellt die allgemeine Vorlage geeignete Standard-Extremwerte entsprechend den Merkmalen des Typs bereit. Beispielsweise gibt std::numeric_limits::min() für den vorzeichenbehafteten Ganzzahltyp int den Mindestwert des Typs zurück und std::numeric_limits::max() den Maximalwert des Typs.

Bei Gleitkommatypen gibt std::numeric_limits::min() den kleinsten positiven Wert dieses Typs zurück und std::numeric_limits::max() gibt den größten endlichen Wert dieses Typs zurück.

Die generische Vorlage stellt auch einige andere Standard-Extremwertinformationen bereit, z. B. Genauigkeit, Rundungsfehler usw. Diese Standard-Extremwerte werden auf der Grundlage der allgemeinen Merkmale des Typs und der Standardspezifikationen definiert.

#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;
}

spezialisierte numerische_Limits

Für bestimmte Datentypen, beispielsweise benutzerdefinierte Klassentypen oder spezielle numerische Typen, gelten diese Standardwerte möglicherweise nicht, da diese Typen möglicherweise unterschiedliche numerische Bereiche oder ein besonderes Verhalten aufweisen. Um diesen Sonderfällen gerecht zu werden, ist eine Spezialisierung von std::numeric_limits verfügbar.

Die Spezialisierung wird durch die Bereitstellung einer speziellen Version einer Vorlage für einen bestimmten Typ erreicht, um Standardeigenschaften und Extrema zu überschreiben. Durch die Spezialisierung von std::numeric_limits können wir benutzerdefinierte Grenzwerte und Attributinformationen für bestimmte Typen bereitstellen.

Das folgende Beispiel zeigt, wie man std::numeric_limits spezialisiert, um benutzerdefinierte Grenzwerte und Attributinformationen für einen benutzerdefinierten Typ MyType bereitzustellen:

#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;
}

Im obigen Beispiel haben wir benutzerdefinierte Mindest- und Höchstwerte für den benutzerdefinierten Typ MyType bereitgestellt, indem wir eine Spezialisierung von std::numeric_limits unter dem std-Namespace definiert haben. Durch Spezialisierung können wir bei Bedarf maßgeschneiderte Extremwert- und Eigenschaftsinformationen für jeden Typ bereitstellen.

Es ist zu beachten, dass es sich bei der Spezialisierung von std::numeric_limits um eine erweiterte Verwendung handelt, die normalerweise beim Umgang mit benutzerdefinierten Typen oder besonderen Anforderungen verwendet wird. Für die meisten grundlegenden Datentypen ist die Standardeinstellung std::numeric_limits normalerweise ausreichend.

Auffüllen

Die allgemeinen numeric_limits und spezialisierten Versionen werden in der Header-Datei <limite> platziert, und die spezialisierten Versionen decken alle numerischen Grundtypen ab.
Die ursprünglichen C-Konstanten sind in <climits>,<limits.h>,<cfloat>,<float.h> definiert
Fügen Sie hier eine Bildbeschreibung einFügen Sie hier eine Bildbeschreibung einFügen Sie hier eine Bildbeschreibung ein

5. Typmerkmal

Typmerkmale (Type Traits) sind eine Reihe von Vorlagenklassen in C++ zum Abrufen und Bearbeiten von Typinformationen zur Kompilierungszeit. Sie bieten eine Möglichkeit, Typprüfungen und -manipulationen zur Kompilierungszeit durchzuführen, sodass der Compiler Vorgänge wie bedingte Kompilierung, Typkonvertierung und Vorlagenspezialisierung basierend auf Typeigenschaften ausführen kann.

Elastische Überladung für Ganzzahltypen

Unter der Annahme, dass es eine Funktion gibt, die tatsächliche Ganzzahl- und Gleitkommaparameter übergeben kann, ist es normalerweise erforderlich, mehrere überladene Funktionen zu schreiben, einschließlich Short, Int, Float, Double usw., was nicht nur umständlich ist, sondern auch das Hinzufügen neuer Typen erfordert, und Type Trait kann es vereinfachen.

#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;
}

Auf diese Weise sind nur zwei Implementierungen erforderlich, um mehrere Parametertypen zu enthalten

Behandeln Sie gängige Typen

Common Type bezieht sich auf den niedrigsten gemeinsamen Typ in einer Gruppe von Typen, die einen konsistenten Typ ausführen und zurückgeben können. In C++ können Sie die Typmerkmalsvorlage „std::common_type“ verwenden, um den niedrigsten gemeinsamen Typ aus einer Reihe von Typen zu erhalten.

Hier ist ein Beispielcode, der zeigt, wie man mit std::common_type gängige Typen verarbeitet:

#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;
}

Im obigen Beispiel definieren wir eine Prozessfunktionsvorlage, die zwei Parameter value1 und value2 akzeptiert und std::common_type verwendet, um den niedrigsten gemeinsamen Typ CommonType dieser beiden Parameter abzurufen. Dann verwenden wir CommonType, um eine Variable result zu deklarieren, addieren value1 und value2 und weisen das Ergebnis result zu. Abschließend geben wir das Ergebnis auf der Konsole aus.

In der Hauptfunktion rufen wir die Prozessfunktion auf, um verschiedene Arten von Parametern zu übergeben, einschließlich Ganzzahlen und Gleitkommazahlen. std::common_type leitet automatisch den niedrigsten gemeinsamen Typ ab und führt eine entsprechende Typkonvertierung und Operation für das Ergebnis durch.

Durch die Verwendung von std::common_type können wir eine Reihe von Parametern mit unterschiedlichen Typen verarbeiten und deren niedrigsten gemeinsamen Typ erhalten, wodurch die Verarbeitung gemeinsamer Typen realisiert wird. Dies ist bei der generischen Programmierung und Template-Metaprogrammierung nützlich, um Operationen für verschiedene Arten von Kombinationen zu verarbeiten.

andere Operationen

für alle Typen

Fügen Sie hier eine Bildbeschreibung ein

für den Klassenunterricht

Fügen Sie hier eine Bildbeschreibung ein

Beachten Sie, dass bool und alle Zeichen als Ganzzahlklassen behandelt werden

Typbeziehung prüfen

Fügen Sie hier eine Bildbeschreibung ein

Typänderung

Fügen Sie hier eine Bildbeschreibung ein

andere

Fügen Sie hier eine Bildbeschreibung ein

Referenz-Wrapper

std::reference_wrapper ist eine Klassenvorlage in der C++-Standardbibliothek, die sich in einer Header-Datei befindet. Es wird zum Umschließen von Referenztypen verwendet und bietet eine einfache Referenzsemantik, die es ermöglicht, Objekte per Referenz zu übergeben und zu manipulieren.

Die Hauptfunktion von std::reference_wrapper besteht darin, den Referenztyp in ein Objekt zu kapseln, sodass es über eine Objektsemantik verfügt. Dies macht es einfach, Referenzen als Funktionsargumente zu übergeben, sie in Containern zu speichern oder sie in anderen Situationen zu verwenden, in denen Objekte erforderlich sind, ohne zusätzliche Zeigersemantik und Speicherverwaltung einzuführen.

Mit std::reference_wrapper können die folgenden Funktionen erreicht werden:

  • Referenzen als Funktionsparameter übergeben: Sie können Referenzen als Funktionsparameter übergeben, ohne Zeiger zu verwenden oder Objekte zu kopieren.
  • Speichern von Referenztypen: Referenztypen können in Containern gespeichert werden, z. B. std::vector<std::reference_wrapper>.
  • Verwendung von Referenzen in Algorithmen: Sie können Referenztypen in Standardbibliotheksalgorithmen verwenden, ohne Zeiger zu verwenden oder Objekte zu kopieren.

Nachfolgend finden Sie einen Beispielcode, der die Verwendung demonstriert

#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;
}

Im obigen Beispiel haben wir eine Inkrementierungsfunktion definiert, die einen Referenzparameter nimmt und ihn erhöht. In der Hauptfunktion erstellen wir eine std::reference_wrapper-Objektreferenz und übergeben ihr die Referenz von num. Dann rufen wir die Inkrementfunktion auf und übergeben ref, eigentlich eine Referenz auf num. Schließlich geben wir den Wert von num aus und sehen, dass er erhöht wurde.

Durch die Verwendung von std::reference_wrapper können wir Referenztypen als Objekte übergeben und bearbeiten und so eine bequemere und flexiblere Referenzsemantik bereitstellen. Es wird häufig in Szenarien wie allgemeiner Programmierung, Funktionsobjekten, STL-Algorithmen usw. verwendet.

Funktionstyp-Wrapper

std::function ist eine in der C++-Standardbibliothek bereitgestellte Klassenvorlage, die zum Kapseln verschiedener Typen aufrufbarer Objekte und zur Bereitstellung einer konsistenten Aufrufschnittstelle verwendet wird.

Die Klassenvorlage für std::function ist wie folgt definiert:

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

Dabei ist R der Rückgabetyp und Args... die Liste der Argumenttypen.

Mithilfe von std::function können Sie ein Funktionsobjekt erstellen, das verschiedene Arten aufrufbarer Entitäten umschließen kann, z. B. Funktionszeiger, Funktionsobjekte, Mitgliedsfunktionszeiger, Lambda-Ausdrücke usw.

std::function bietet die folgenden Hauptfunktionen und Verwendungsmöglichkeiten:

  • Kapselung aufrufbarer Objekte: std::function kann verwendet werden, um verschiedene aufrufbare Objekte in ein einheitliches Funktionsobjekt zu kapseln, sodass sie über dieselbe aufrufende Schnittstelle verfügen.
  • Aufrufbare Objekte speichern und weitergeben: std::function-Objekte können wie gewöhnliche Objekte kopiert, gespeichert und weitergegeben werden. Dies macht es ideal für die Übergabe aufrufbarer Objekte als Argumente an Funktionen, die in Containern gespeichert werden, oder als Klassenmitgliedsvariablen.
  • Polymorpher Aufruf: Durch std::function können verschiedene Arten von aufrufbaren Objekten auf einheitliche Weise aufgerufen werden, ohne sich um ihre spezifischen Typen zu kümmern. Dadurch wird der Code flexibler und erweiterbarer.

Hier ist ein Beispiel, das die Verwendung von std::function zeigt:

#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;
}

Im obigen Beispiel haben wir zunächst eine Add-Funktion und eine Foo-Klasse definiert, wobei die Foo-Klasse über eine Mitgliedsfunktion multiply verfügt. Dann deklarieren wir ein std::function-Objekt func, dessen Funktionstyp int(int, int) ist.

Wir weisen zunächst die Add-Funktion func zu, rufen dann mit func die Add-Funktion auf und geben das Ergebnis aus. Als nächstes binden wir die Mitgliedsfunktion multiply der Foo-Klasse mithilfe von std::bind an func und übergeben dabei einen Objektzeiger der Foo-Klasse und zwei Platzhalter als Parameter. Abschließend rufen wir Foo::multiply mit func auf und geben das Ergebnis aus.


Platzhalter sind spezielle Objekte in der C++-Standardbibliothek, die die Parameterpositionen von Funktionsobjekten belegen. Im Funktionsobjekt gibt der Platzhalter an, dass der Parameter an dieser Position beim tatsächlichen Aufruf durch den entsprechenden Wert ersetzt wird.

Bei der Verwendung von std::bind werden die Platzhalter std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 und weitere sukzessive aufsteigende Platzhalter _4, _5 usw. verwendet, um die Parameterpositionen des Funktionsobjekts zu identifizieren. Mit Platzhaltern können wir die Position des Parameters beim Binden der Funktion angeben, ohne den tatsächlichen Parameterwert anzugeben.

Im Beispielcode verwenden wir zwei Platzhalter std::placeholders::_1 und std::placeholders::_2:

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

Hier binden wir die Memberfunktion Foo::multiply an func und verwenden zwei Platzhalter, um die Position der Parameter anzugeben. Das bedeutet, dass beim Aufruf von func die Argumente anstelle der Platzhalter übergeben werden.

Beim tatsächlichen Aufruf von func(3, 4) entspricht der Platzhalter std::placeholders::_1 dem ersten Parameter, der 3 ist, und der Platzhalter std::placeholders::_2 entspricht dem zweiten Parameter, der 4 ist. Daher werden die Parameter 3 und 4 als tatsächliche Parameter an die Memberfunktion Foo::multiply übergeben.

Durch die Verwendung von Platzhaltern können Funktionsobjekte flexibler gestaltet werden, insbesondere im Hinblick auf die Bindung von Funktionsobjekten und die Zuordnung von Parameterpositionen. Es ermöglicht uns, die Übergabe von Parametern zu verzögern und Parameterwerte dynamisch bereitzustellen, wenn das Funktionsobjekt aufgerufen wird.

Es ist zu beachten, dass Anzahl und Position der Platzhalter mit der Anzahl und Position der Parameter des Funktionsobjekts übereinstimmen sollten. Andernfalls kommt es zu falschen Parameterübergaben oder Kompilierungsfehlern.

Im Beispiel werden Platzhalter verwendet, um das gebundene Funktionsobjekt mit dem foo-Objekt und den Parameterpositionen zu verknüpfen. Wenn wir auf diese Weise das gebundene Funktionsobjekt aufrufen, ruft es die Multiplikationsfunktion für das foo-Objekt auf und übergibt die entsprechenden Positionsargumente an die Funktion.


Durch std::function können wir verschiedene Arten von aufrufbaren Objekten in einem einheitlichen Objekt kapseln und sie auf einheitliche Weise aufrufen. Dies sorgt für mehr Flexibilität und Allgemeingültigkeit und macht die Verwendung von Funktionsobjekten komfortabler und erweiterbarer.

6. Hilfsfunktionen

Maximum und Minimum

Alle minmax()-Funktionen und alle Funktionen mit Anfangswertspalten beginnen mit c++11
Fügen Sie hier eine Bildbeschreibung ein. Wenn wir Funktionen in Header-Dateien verwenden, müssen wir normalerweise Vergleichsfunktionen (oder Prädikate) angeben, um die Reihenfolge der Elemente zu bestimmen oder andere Bedingungen zu erfüllen. Eine Vergleichsfunktion ist ein aufrufbares Objekt, das zwei Argumente entgegennimmt und einen booleschen Wert zurückgibt, der die Reihenfolge zweier Elemente vergleicht.

benutzerdefinierter Vergleich

Hier ist ein Beispiel für die Sortierung mithilfe von Vergleichsfunktionen:


#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;
}

Im obigen Beispiel haben wir eine Vergleichsfunktion cmp definiert, die Elemente nach ihrem Absolutwert vergleicht. Anschließend sortieren wir den Nums-Container mit der Funktion std::sort und übergeben die Funktion cmp als Vergleichsfunktion.

Die Sortierergebnisse werden nach dem Absolutwert der Elemente von klein nach groß sortiert und die Ausgabeergebnisse sind: -1, 2, -3, 4, -5.

Durch Anpassen der Vergleichsfunktion können wir Elemente nach bestimmten Bedingungen sortieren oder vergleichen. Dies ist bei vielen Algorithmen und Vorgängen nützlich, z. B. bei benutzerdefinierten Sortierreihenfolgen, beim Filtern von Elementen nach bestimmten Regeln und mehr. Je nach Bedarf können wir unterschiedliche Vergleichsfunktionen schreiben, um eine bestimmte Sortier- oder Vergleichslogik zu erfüllen.

zwei Werte vertauschen

std::swap ist eine allgemeine Swap-Funktion in der C++-Standardbibliothek, die sich in der Header-Datei befindet.

Die Funktion std::swap verfügt über mehrere überladene Versionen zum Austausch von Objekten unterschiedlichen Typs. Seine generische Vorlage ist wie folgt definiert:

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

Dabei ist T der Typ des auszutauschenden Objekts und a und b Verweise auf die auszutauschenden Objekte.

Beim Aufruf von std::swap(a, b) wählt der Compiler je nach tatsächlichem Objekttyp die entsprechende überladene Version aus, um den Swap-Vorgang auszuführen. std::swap verfügt bereits über Standardspezialisierungsdefinitionen für integrierte Typen und Typen, die von der Standardbibliothek bereitgestellt werden.

Darüber hinaus können wir für einen benutzerdefinierten Typ die Swap-Operation des benutzerdefinierten Typs implementieren, indem wir eine spezielle Version des Typs definieren oder eine benutzerdefinierte Swap-Funktion bereitstellen. Zum Beispiel:

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

Durch die Bereitstellung einer Spezialisierung des benutzerdefinierten Typs MyType im std-Namespace können wir die Funktion std::swap überladen, um beim Austauschen von Objekten des benutzerdefinierten Typs einen bestimmten Auslagerungsvorgang auszuführen.

Das Folgende ist ein Beispiel für den Werteaustausch mit 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;
}

Im obigen Beispiel haben wir zwei ganzzahlige Variablen a und b definiert und auf 10 bzw. 20 initialisiert. Dann haben wir die Werte von a und b mit der Funktion std::swap vertauscht.

Die Ausgabe ist:

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

Durch die Verwendung von std::swap können wir die Werte zweier Objekte bequem austauschen, ohne explizit temporäre Variablen oder benutzerdefinierte Swap-Funktionen schreiben zu müssen. Dies ist in vielen Situationen sehr nützlich, beispielsweise bei Sortieralgorithmen, Containeroperationen usw., in denen Werte ausgetauscht werden müssen. Seit C++11 stellt die Standardbibliothek eine überladene Version für Array bereit . Darüber hinaus können für benutzerdefinierte Typen benutzerdefinierte Austauschoperationen durch Überladen von Operator= implementiert werden.

Zusammenfassend ist std::swap eine allgemeine Austauschfunktion der C++-Standardbibliothek, mit der Objekte unterschiedlichen Typs ausgetauscht werden können. Es gibt bereits Standardspezialisierungsdefinitionen für integrierte Typen und Typen, die von der Standardbibliothek bereitgestellt werden. Für einen benutzerdefinierten Typ können wir die Swap-Operation des benutzerdefinierten Typs über eine spezielle Version oder eine benutzerdefinierte Swap-Funktion implementieren.

Vergleichsoperator

In C++11 können die folgenden Operatoren verwendet werden, um das Größenverhältnis zweier Objekte zu vergleichen:

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

Diese Operatoren können für integrierte Typen (z. B. Ganzzahlen, Gleitkommazahlen usw.) und benutzerdefinierte Typen verwendet werden, sofern die entsprechenden Operatorüberladungen definiert sind oder die Objekte die relevanten Vergleichsoperationen unterstützen.

Hier ist ein Beispiel, das zeigt, wie diese Operatoren zum Vergleich zweier Ganzzahlen verwendet werden:

#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;
}

Die Ausgabe ist:

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

Im obigen Beispiel vergleichen wir zwei ganze Zahlen a und b und geben eine entsprechende Nachricht basierend auf ihrer Größenbeziehung aus. Beachten Sie, dass Sie den entsprechenden Vergleichsoperator überladen müssen, wenn Sie Objekte eines benutzerdefinierten Typs vergleichen möchten.

7.Klassenverhältnis<>

std::ratio ist eine Vorlagenklasse in der C++-Standardbibliothek zur Darstellung von Verhältnissen rationaler Zahlen. Es steht in der Header-Datei.

Die Vorlagenklasse std::ratio ist wie folgt definiert:


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

Unter diesen stellt Num den Zähler dar, Denom den Nenner und der Standardwert ist 1. Sowohl Num als auch Denom müssen ganzzahlige Typen sein.

Die Vorlagenklasse std::ratio bietet eine Möglichkeit, Verhältnisse rationaler Zahlen zur Kompilierungszeit darzustellen, die zum Durchführen von Einheitenumrechnungen, Berechnen von Verhältnisbeziehungen und mehr verwendet werden kann. Seine Hauptaufgabe besteht darin, einen statischen Typ zur Kompilierungszeit bereitzustellen, um gängige proportionale Beziehungen darzustellen, ohne dass Laufzeitberechnungen erforderlich sind.

Hier ist ein Beispiel mit 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;
}

Die Ausgabe ist:

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

In diesem Beispiel definieren wir drei Aliase für den Typ std::ratio: one_half für 1/2, one_third für 1/3 und two_thirds für 1/3 + 1/3.

Durch Zugriff auf die statischen Mitgliedsvariablen num und den der Klasse std::ratio können wir den Zähler und den Nenner des Verhältnisses rationaler Zahlen ermitteln und ausgeben.

Ausdruck

Fügen Sie hier eine Bildbeschreibung ein

vordefinierte Einheiten

Die Header-Dateien in der C++-Standardbibliothek stellen einige vordefinierte std::ratio-Einheiten bereit, die zur Darstellung allgemeiner proportionaler Beziehungen verwendet werden.
Fügen Sie hier eine Bildbeschreibung ein
Diese vordefinierten Einheiten erleichtern die Darstellung physikalischer Größen und können direkt für die Einheitenumrechnung und Verhältnisberechnungen verwendet werden. Beispielsweise stellt std::kilo tausend dar, und Sie können einen Wert mit std::kilo multiplizieren, um ihn in tausend umzuwandeln.

Es ist zu beachten, dass std::ratio ein Typ ist, der zur Kompilierungszeit berechnet wird, sein Wert zur Kompilierungszeit bestimmt wird und keine arithmetischen Laufzeitoperationen unterstützt. Es wird hauptsächlich zur Einheitenumrechnung und Verhältnisberechnung zur Kompilierungszeit verwendet und bietet beispielsweise ein breites Anwendungsspektrum in der Vorlagenmetaprogrammierung und der statischen Typprüfung.

8. Uhr und Timer

Header-Dateien wurden in C++11 eingeführt, um Funktionen im Zusammenhang mit Clock und Timer zum Messen der Zeit und zum Implementieren von Timern bereitzustellen.

Dauer (Zeitraum)

Die Header-Dateien in C++11 führen die Klassenvorlage std::chrono::duration zur Darstellung von Zeitintervallen oder Dauern ein. std::chrono::duration ist eine allgemeine Zeitmengenklasse, die zur Darstellung von Zeitintervallen in verschiedenen Einheiten wie Sekunden, Millisekunden, Mikrosekunden usw. verwendet werden kann.

Der Vorlagenparameter von std::chrono::duration besteht aus zwei Teilen: Rep und Period. Rep stellt den zugrunde liegenden Typ des Zeitintervalls dar, normalerweise einen arithmetischen Typ (z. B. int, double usw.), und Period stellt die Einheit des Zeitintervalls dar. Period ist eine Instanz des Typs std::ratio, der zur Darstellung der proportionalen Beziehung zwischen Zähler und Nenner verwendet wird, die die Einheit des Zeitintervalls bestimmt.

Hier ist ein Beispiel mit 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;
}

In diesem Beispiel erstellen wir zwei std::chrono::duration-Objekte unterschiedlichen Typs: eine Dauer vom Typ Integer mit einer Dauer von 5 Sekunden und eine Dauer vom Typ Double mit einer Dauer von 2,5 Sekunden. Wir verwenden die Mitgliedsfunktion count(), um den Wert der Dauer zu erhalten, und verwenden std::chrono::duration_cast für die Einheitenumrechnung.

Die Ausgabe ist:

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

Fügen Sie hier eine Bildbeschreibung einFügen Sie hier eine Bildbeschreibung ein

Durch die Verwendung von std::chrono::duration können Zeitintervalle einfach berechnet, konvertiert und dargestellt werden, ohne dass Umrechnungen zwischen verschiedenen Einheiten manuell verwaltet werden müssen.

Uhr

Die Uhr ist ein Maßstab für die Zeitmessung. C++11 bietet drei Arten von Uhren:

  • std::chrono::system_clock: wird verwendet, um die aktuelle Zeit des Systems darzustellen.
  • std::chrono::steady_clock: wird verwendet, um eine relativ stabile Zeit darzustellen und wird von der Systemzeit nicht beeinflusst.
  • std::chrono::high_resolution_clock: Stellt eine hochpräzise Uhr bereit, die ein Alias ​​für system_clock oder steady_clock sein kann.

Diese Uhren stellen die Mitgliedsfunktion now() bereit, um die aktuelle Uhrzeit abzurufen.

Hier ist ein Beispiel mit 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;
}

In diesem Beispiel verwenden wir std::chrono::steady_clock, um die Start- und Endzeitpunkte zu ermitteln, und berechnen den Zeitunterschied zwischen ihnen, um die Ausführungszeit des Programms zu ermitteln.
Fügen Sie hier eine Bildbeschreibung ein

Timer

C++11 stellt keine Standardbibliotheksklasse für Timer bereit, Sie können jedoch Clock und einige andere Funktionen verwenden, um Timerfunktionen zu implementieren. Sie können beispielsweise die Funktion std::this_thread::sleep_for() verwenden, um den Thread für einen bestimmten Zeitraum schlafen zu lassen, um eine einfache Timer-Funktion zu implementieren.

Hier ist ein Beispiel für die Implementierung eines Timers mit 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;
}

In diesem Beispiel verwenden wir die Funktion std::this_thread::sleep_for(), um das Programm für eine Sekunde in den Ruhezustand zu versetzen und auszugeben, wie oft der Timer ausgelöst wird. Das Programm beendet den Timer, wenn der Zähler den Zielwert erreicht.

Es ist wichtig zu beachten, dass die Implementierung von Timern je nach Betriebssystem und Compiler variieren kann. Das obige Beispiel stellt nur eine einfache Implementierungsmethode dar. In tatsächlichen Anwendungen sind möglicherweise komplexere Timerfunktionen erforderlich, die je nach spezifischen Anforderungen erweitert und optimiert werden können.
Fügen Sie hier eine Bildbeschreibung ein

Funktion in C

Ursprünglich in <time.h> enthaltene Definitionen sind jetzt in <ctime> enthalten
Fügen Sie hier eine Bildbeschreibung ein

Umrechnung zwischen Zeitpunkt und Kalenderzeit

In der Header-Datei von C++ 11 kann die Klassenvorlage std::chrono::time_point zur Darstellung des Zeitpunkts (Time Point) verwendet werden. Ein Zeitpunkt ist ein abstraktes Konzept eines bestimmten Zeitpunkts, der der Kalenderzeit entspricht.

Zur Konvertierung zwischen einem Zeitpunkt und einer Kalenderzeit können folgende Funktionen und Typen verwendet werden:

  • std::chrono::system_clock: std::chrono::system_clock ist ein Uhrentyp, der zur Darstellung der aktuellen Zeit des Systems verwendet wird. Es kann verwendet werden, um die aktuelle Kalenderzeit abzurufen.

  • std::chrono::time_point: std::chrono::time_point ist eine Klassenvorlage, die einen Zeitpunkt darstellt. Es kann verwendet werden, um Werte zu bestimmten Zeitpunkten zu speichern und zu manipulieren.

  • std::chrono::duration: std::chrono::duration ist eine Klassenvorlage, die ein Zeitintervall darstellt. Daraus lässt sich die Differenz zwischen den Zeitpunkten berechnen.

Hier ist eine Beispielkonvertierung zwischen einem Zeitpunkt und einer Kalenderzeit:

#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;
}

In diesem Beispiel verwenden wir zunächst std::chrono::system_clock::now(), um den aktuellen Zeitpunkt abzurufen, und verwenden dann std::chrono::system_clock::to_time_t(), um den Zeitpunkt in Kalenderzeit (Typ std::time_t) umzuwandeln. Als nächstes konvertieren wir die Kalenderzeit mit std::chrono::system_clock::from_time_t() zurück in einen Zeitpunkt. Abschließend geben wir die konvertierte Kalenderzeit mit std::asctime() an den Standardausgabestream aus.

Beachten Sie, dass Zeitpunkt und Kalenderzeit in Präzision und Bereich variieren können. Zeitpunkte haben im Allgemeinen eine höhere Genauigkeit und einen höheren Bereich, während Kalenderzeiten auf die Genauigkeit und den Bereich des Typs std::time_t beschränkt sind.

Mithilfe der Konvertierung zwischen Zeitpunkt und Kalenderzeit können Sie problemlos verschiedene Zeitdarstellungen konvertieren und zwischen ihnen arbeiten, um unterschiedlichen Anforderungen gerecht zu werden.

Timer werden häufig in Threads verwendet. Dieser Teil wird im Thread-Kapitel später ausführlich beschrieben

9. Einige wichtige Header-Dateien

<cstddef>

Die Headerdatei <cstddef> definiert einige Typen und Funktionen im Zusammenhang mit Größen- und Zeigeroperationen
Fügen Sie hier eine Bildbeschreibung ein

<cstdlib>

Die Header-Datei definiert einige gängige Bibliotheksfunktionen, z. B. Speicherverwaltungsfunktionen (z. B. malloc und free), Typkonvertierungsfunktionen (z. B. atoi und atof), Zufallszahlenfunktionen (z. B. rand und srand) und andere gängige Funktionen.
Fügen Sie hier eine Bildbeschreibung ein

<cstring>

Die Headerdatei <cstring> definiert einige Funktionen und Typen im Zusammenhang mit der String-Manipulation, z. B. String-Kopierfunktionen (wie strcpy und strncpy), String-Verkettungsfunktionen (wie strcat und strncat), String-Vergleichsfunktionen (wie strcmp und strncmp) und andere String-Verarbeitungsfunktionen.
Fügen Sie hier eine Bildbeschreibung ein

Beispiel

#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;
}

Dieses Beispiel zeigt, wie , und Header-Dateien für primitive Typen, Bibliotheksfunktionen und String-Manipulation verwendet werden. Beachten Sie, dass bei der Arbeit mit Zeichenfolgen in C++ die Verwendung der Klasse std::string anstelle herkömmlicher Zeichenfolgen im C-Stil (dargestellt als Zeichenarrays) empfohlen wird, um sicherere und bequemere Funktionen zur Zeichenfolgenmanipulation zu gewährleisten.

  • Ende von Kapitel fünf

Ich denke du magst

Origin blog.csdn.net/qq_44616044/article/details/131223759
Empfohlen
Rangfolge