Templates



  • SeppJ schrieb:

    Cpp_Anfaeger schrieb:

    Ja, es stimmt mit der Logik nicht

    So ist es. Aber dein neuer Vorschlag ist ja fast noch schlimmer. Denk nicht so technisch. Halte dich an die mathematische Definition eines Minimums, die ist schon gut gewählt.

    Wie kann ich denn sonst die Gleichheit feststellen, wenn der Benutzer 2 gleiche Objekte eingibt? Ich muss doch diese Möglichkeit mitberücksichtigen.



  • Cpp_Anfaeger schrieb:

    SeppJ schrieb:

    Cpp_Anfaeger schrieb:

    Ja, es stimmt mit der Logik nicht

    So ist es. Aber dein neuer Vorschlag ist ja fast noch schlimmer. Denk nicht so technisch. Halte dich an die mathematische Definition eines Minimums, die ist schon gut gewählt.

    Wie kann ich denn sonst die Gleichheit feststellen, wenn der Benutzer 2 gleiche Objekte eingibt? Ich muss doch diese Möglichkeit mitberücksichtigen.

    Nein wozu?
    min(5,5) == 5



  • qweasdyxc schrieb:

    Cpp_Anfaeger schrieb:

    SeppJ schrieb:

    Cpp_Anfaeger schrieb:

    Ja, es stimmt mit der Logik nicht

    So ist es. Aber dein neuer Vorschlag ist ja fast noch schlimmer. Denk nicht so technisch. Halte dich an die mathematische Definition eines Minimums, die ist schon gut gewählt.

    Wie kann ich denn sonst die Gleichheit feststellen, wenn der Benutzer 2 gleiche Objekte eingibt? Ich muss doch diese Möglichkeit mitberücksichtigen.

    Nein wozu?
    min(5,5) == 5

    Theoretisch, ja, wenn man nur den Wert betrachtet... aber wenn ich etwas hätte, wo ich nicht vorher weiß, was drin ist (2 Blackboxen), dann weiß ich nicht, wie miteinander verglichen wird, oder?



  • Cpp_Anfaeger schrieb:

    aber wenn ich etwas hätte, wo ich nicht vorher weiß, was drin ist (2 Blackboxen), dann weiß ich nicht, wie miteinander verglichen wird, oder?

    Ah, und das Problem löst man, indem man beide Blackboxes addiert? 😮

    Ne, Blackbox funktioniert wunderbar hier. Alles, was einen < -Operator anbietet, kann zur Berechnung eines Minimums benutzt werden.

    const T& min(const T& lhs, const T& rhs)
    {
        if (lhs < rhs)
            return lhs;
        else
            return rhs;
    }
    

    Schau auch, dass du const T& und nicht const T zurückgibst. Top-Level-CV-Qualifikationen bei Rückgabetypen und Parametern sind nämlich sinnlos.



  • Nexus schrieb:

    Top-Level-CV-Qualifikationen bei Rückgabetypen und Parametern sind nämlich sinnlos.

    ich bin mir nicht sicher ob ich das richtige anspreche und es auch korrekt in erinnerung habe - verzeih mir wenn nicht - aber z.b. ein fall wo die top-level-cv-qualifier beim rückgabetypen einen unterschied machen:

    struct Foo
    {
    	int MyData;
    	Foo(int Data)
    		: MyData(Data)
    	{
    	}
    };
    const Foo operator+ (Foo const& Lhs, Foo const& Rhs)
    {
    	return Foo(Lhs.MyData + Rhs.MyData);
    }
    void Func(Foo const& Lhs, Foo const& Rhs)
    {
    	if((Lhs + Rhs).MyData = 0) // Ups, sollte ein Vergleich werden. Kompiliert dank const nicht.
    	{
    		// ...
    	}
    }
    


  • [quote="Nexus"] Ne, Blackbox funktioniert wunderbar hier. Alles, was einen < -Operator anbietet, kann zur Berechnung eines Minimums benutzt werden.

    const T& min(const T& lhs, const T& rhs)
    {
        if (lhs < rhs)
            return lhs;
        else
            return rhs;
    }
    

    Das geht so nicht, weil mein Anliegen anders ist ... es geht mir darum sagen zu können, welches "Objekt" kleiner ist u. nicht welcher Wert. Also es geht mir nicht um den Wert (klar über den Wert schließe ich auf das Objekt zurück) und mit dieser Rückgabe habe ich keine Feststellmöglichkeit. Ich weiß, das ist blöd ausgedrückt.



  • ich hab absolut keine ahnung was das bringen soll aber werd glücklich damit:

    template<typename T>
    T const* MyMin(T const* Lhs, T const* Rhs)
    {
        if(*Lhs < *Rhs)
        {
            return Lhs;
        }
        if(*Rhs < *Lhs)
        {
            return Rhs;
        }
        return nullptr;
    }
    

    das kann man nun noch für char const* template-spezialisieren und einen lexicographischen vergleich einfügen. keine lust das nun vorzumachen weil ich den sinn beim besten willen nicht sehe.



  • asfsdaf schrieb:

    z.b. ein fall wo die top-level-cv-qualifier beim rückgabetypen einen unterschied machen:

    Durch das const verschlimmerst du die Situation. Indem du einen Fehler verhinderst, der nie passiert, deaktivierst du auch gleich Move-Semantik. Siehe hier...

    Cpp_Anfaeger schrieb:

    Das geht so nicht, weil mein Anliegen anders ist ... es geht mir darum sagen zu können, welches "Objekt" kleiner ist u. nicht welcher Wert.

    Darum Referenz und nicht Kopie. Wie du von diesem Anliegen darauf kommst, 0 oder die Summe beider Werte zurückzugeben (was absolut keinen Bezug zum Objekt mehr darstellt), verstehe ich erst recht nicht.

    Davon abgesehen, welche Anwendung hat eine so abwegig definierte Minimumsfunktion? Wozu brauchst du das?



  • lol davon wusste ich nichts, bin auch effective c++ zum opfer gefallen. danke für die aufklärung. nun hab ich erstmal einiges an code zu ändern...



  • Nexus schrieb:

    Cpp_Anfaeger schrieb:

    Das geht so nicht, weil mein Anliegen anders ist ... es geht mir darum sagen zu können, welches "Objekt" kleiner ist u. nicht welcher Wert.

    Darum Referenz und nicht Kopie. Wie du von diesem Anliegen darauf kommst, 0 oder die Summe beider Werte zurückzugeben (was absolut keinen Bezug zum Objekt mehr darstellt), verstehe ich erst recht nicht

    Danke, ihr habt sicher recht. Es ist nicht richtig, einfach irgendetwas zu schnappen, nur um schnell damit zu basteln, was man später nicht mehr nachvollziehen kann.

    **Edit:

    asfsdaf schrieb:

    ich hab absolut keine ahnung was das bringen soll aber werd glücklich damit:

    template<typename T>
    T const* MyMin(T const* Lhs, T const* Rhs)
    {
        if(*Lhs < *Rhs)
        {
            return Lhs;
        }
        if(*Rhs < *Lhs)
        {
            return Rhs;
        }
        return nullptr;
    }
    

    das kann man nun noch für char const* template-spezialisieren und einen lexicographischen vergleich einfügen. keine lust das nun vorzumachen weil ich den sinn beim besten willen nicht sehe.

    nullptr ... finde ich gut 👍 ... hatte ich bisher 0 oder NULL geschrieben



  • asfsdaf schrieb:

    ich hab absolut keine ahnung was das bringen soll aber werd glücklich damit:

    template<typename T>
    T const* MyMin(T const* Lhs, T const* Rhs)
    {
        if(*Lhs < *Rhs)
        {
            return Lhs;
        }
        if(*Rhs < *Lhs)
        {
            return Rhs;
        }
        return nullptr;
    }
    

    das kann man nun noch für char const* template-spezialisieren und einen lexicographischen vergleich einfügen. keine lust das nun vorzumachen weil ich den sinn beim besten willen nicht sehe.

    Ich habe es soeben mit dem Keywort lexicographical_compare() versucht. Irgendwie blicke ich nicht durch, was da für Ergebnisse heraus kommen.

    Ich habe versucht die Template-Funktion zu überladen und verschiedene Value-Werte hin durchgeschickt.

    ... ***Edit --> siehe unten
    


  • Ein weiterer Anlauf ...

    Ich habe die Templatefunktion angepasst (Referenz-Parameter anstatt Zeiger), damit der Aufruf der Funktionen in main() einheitlich wird.

    Es läuft soweit - glaube ich - nur mit Ausgabe stimmt was nicht, wenn ich Strings nach C-Style in die Funktion findMinimum() reinschicke.

    Hat jemand eine Idee, was da vor sich geht?

    #include <iostream>
    #include <string>
    #include <string.h>	// wegen strcmp()
    using namespace std;
    
    //------------------------------------------------------------------------
    // Template-Funktion vergleicht zwei Werte miteinander (ohne char*)
    //------------------------------------------------------------------------
    template <typename T>
    
    T const* findMinimum(const T &value1, const T &value2, int &templ_nr) {
    	templ_nr = 1;
    	if (value1 < value2) {
    		return &value1;
    	}
    	if (value1 > value2) {
    		return &value2;
    	}
    	return nullptr; // wenn beide gleich
    }
    
    //------------------------------------------------------------------------
    // Überladung mit normaler Funktion (vergleicht char*)
    //------------------------------------------------------------------------
    const char *findMinimum(const char *value1, const char *value2, int &templ_nr) {
    	templ_nr = 2;
    
    	/*
    	// Meine Methode
    	string v1 = value1;
    	string v2 = value2;
    	if (v1 < v2) {
    		return value1;
    	}
    	if (v1 > v2) {
    		return value2;
    	}
    	*--------------------------*/
    
    	// strcmp - Methode
    	bool result = strcmp(value1, value2);
    	if (result < 0) {
    		return value1;
    	}
    	if (result > 0) {
    		return value2;
    	}
    
    	//*---------------------------*/
    
    	/*
    	// lexicographical_compare - Methode
    	bool result = lexicographical_compare(value1, value1 + sizeof(value1),
    										  value2, value2 + sizeof(value2) );
    	if (result == true) {
    		return value1;
    	} else {  // umdrehen, ob eventuell der andere Wert größer ist
    		bool result = lexicographical_compare(value2, value2 + sizeof(value2) ,
    											  value1, value1 + sizeof(value1) );
    		if (result == true) {
    			return value2;
    		}
    	}
    	*/
    
    	return nullptr; // wenn kein Min gefunden -> beide gleich
    }
    
    //------------------------------------------------------------------------
    // Hauptfunkt.
    //------------------------------------------------------------------------
    int main() {
    	/* Testbespiele
    	string value1 = "Muenchen"; // C++ Style
    	string value2 = "Aachen";
    
    	int value1 = 2;
    	int value2 = 100;
    
    	const char *value1 = "Muenchen";	// C-Style
    	const char *value2 = "Aachen";
    
    	const char value1[] = "Aachen";		// C-Style
    	const char value2[] = "Muenchen";
    	*/
    
    	const char value1[] = "baaaaaaaaab"; // C-Style
    	const char value2[] = "baaa";
    
    	int templ_nr = 0;
    	cout << "Objekt1-Ort: " << &value1 << "  Inhalt: " << value1 << endl;
    	cout << "Objekt2-Ort: " << &value2 << "  Inhalt: " << value2 << endl << endl;
    
    	// Compiler wählt autom. eine passende Methode:
    	auto *smallest = findMinimum(value1, value2, templ_nr);
    
    	cout << "Template Nr. " << templ_nr << " wurde aufgerufen." << endl << endl;
    
    	if (smallest != nullptr) {
    		// hier stimmt was nicht mit der Ausgabe, ???
    		// wenn es sich um char* handelt
    		cout << "Der kleinere Wert ist: " << *smallest
    			 << " und befindet sich im Objekt: " << smallest << endl;
    	} else {
    		cout << "Inhalte von beiden sind gleich!" << endl;
    	}
    
    	getwchar();
    	return 0;
    }
    


  • Dein Programm funktioniert einwandfrei.
    Und der Header für strcmp heißt übrigens cstring.



  • Nathan schrieb:

    Dein Programm funktioniert einwandfrei.
    Und der Header für strcmp heißt übrigens cstring.

    Danke für dein Feedback. Vermutlich liegt es dann beim Code::Blocks 12.11, ich probiere es heute abend mal auf Netbeans und VS aus.


  • Mod

    Cpp_Anfaeger schrieb:

    Danke für dein Feedback. Vermutlich liegt es dann beim Code::Blocks 12.11, ich probiere es heute abend mal auf Netbeans und VS aus.

    Nein, das liegt weder an deiner IDE (die damit überhaupt gar nichts zu tun hat) noch direkt an deinem Compiler (bzw. der Standardbibliothek, die dieser mitbringt). Das liegt da dran, dass string.h auch korrekt ist, sofern man sich auf die Kompatiblitätsfeatures von C++ verlässt. Diese sind jedoch ausdrücklich "deprecated":

    C++11, appendix D, 2 schrieb:

    These are deprecated features, where deprecated is defined as: Normative for the current edition of the
    Standard, but not guaranteed to be part of the Standard in future revisions.

    C++11, appendix D.5 schrieb:

    1. For compatibility with the C standard library and the C Unicode TR, the C++ standard library provides
      the 25 C headers, as shown in Table 154.

    Table 154 — C headers
    <assert.h>
    <complex.h>
    <ctype.h>
    <errno.h>
    <fenv.h>
    <float.h>
    <inttypes.h>
    <iso646.h>
    <limits.h>
    <locale.h>
    <math.h>
    <setjmp.h>
    <signal.h>
    <stdalign.h>
    <stdarg.h>
    <stdbool.h>
    <stddef.h>
    <stdint.h>
    <stdio.h>
    <stdlib.h>
    <string.h>
    <tgmath.h>
    <time.h>
    <uchar.h>
    <wchar.h>
    <wctype.h>

    1. Every C header, each of which has a name of the form name.h, behaves as if each name placed in the standard
      library namespace by the corresponding cname header is placed within the global namespace scope. It is
      unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace
      std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).
    2. [ Example: The header <cstdlib> assuredly provides its declarations and definitions within the namespace
      std. It may also provide these names within the global namespace. The header <stdlib.h> assuredly
      provides the same declarations and definitions within the global namespace, much as in the C Standard. It
      may also provide these names within the namespace std. — end example ]

    Aber eigentlich heißt der Header cstring:

    C++11, 21.7 schrieb:

    1. Tables 74, 75, 76, 77, 78, and 79 describe headers <cctype>, <cwctype>, <cstring>, <cwchar>, <cstdlib>
      (character conversions), and <cuchar>, respectively.
    2. The contents of these headers shall be the same as the Standard C Library headers <ctype.h>, <wctype.h>,
      <string.h>, <wchar.h>, and <stdlib.h> and the C Unicode TR header <uchar.h>, respectively, with the
      following modifications:
      [...]


  • Danke, ich habe die Headerdatei gegen cstring ausgewechselt, aber in der Ausgabe steht immer noch was Falsches 😕

    Der kleinere Wert ist: b (es müsste aber nach meinem Verständis stehen: baaa)

    und befindet sich im Objekt: baaa (es müsste aber hier die Adresse der betreff. Variablen stehen: 0x....)



  • Du gibst char* aus, das verhält sich bezüglich I/O anders als T* . Es wird nämlich als String interpretiert. Mit der Dereferenzierung hast du ein einzelnes Zeichen vom Typ char .

    Um die Adresse auszugeben, benutze static_cast<void*> .



  • Nexus schrieb:

    Du gibst char* aus, das verhält sich bezüglich I/O anders als T* . Es wird nämlich als String interpretiert. Mit der Dereferenzierung hast du ein einzelnes Zeichen vom Typ char .

    Um die Adresse auszugeben, benutze static_cast<void*> .

    Ich weiß nicht, ob das syntaktisch richtig ist:

    error: invalid static_cast from type 'const char' to type 'void'**



  • const vergessen



  • Nexus schrieb:

    const vergessen

    Oh Mann ... zu blöd, um die Fehlermeldung zu interpretieren. Danke für den Hinweis 🙂

    Ich habe es angewendet:

    cout << "Der kleinere Wert ist: " << static_cast <const char*> (smallest)
         << " und befindet sich im Objekt: " << static_cast <const void*> (smallest)  << endl;
    

    Leider klappt es sauber wieder nur für:

    const char value1[] = "Aachen";     // C-Style
        const char value2[] = "Muenchen";
    

    bei der Form zeigt er eine andere Adresse an:

    const char *value1 = "Muenchen";    // C-Style
        const char *value2 = "Aachen";
    

    und für die Form kratzt er ganz ab:

    int value1 = 2;
        int value2 = 100;
    

    Ist doch zum Mäuse-Melken diese ganzen Zeiger 😡

    Ich versuche die ganze Zeit es so hinzubekommen, dass ich die Funktion findMinimum() einheitlich immer auf dieselbe Art und Weise verwenden kann, egal was man als Parameter übergibt. Und rauskommen soll es auch einheitlich, ohne nachdenken zu müssen, ob ich was für einen Typ habe.


Anmelden zum Antworten