[Spiel] Findet die Fehler ...



  • templatefehler kann man schlecht nach schwierigkeit einordnen, hier mal was was ich als leicht bezeichnen würde

    template<class T>
    struct Helper
    {
        template<class U>
        static U function(const T& t)
        {
             return t.bar();
        }
    };
    
    template<class U,class T>
    U foobar(const T& t)
    {
        return Helper<T>::function<U>(t);
    }
    
    struct Test
    {
        int bar()const
        {
            return 5;
        }
    };
    
    int main()
    {
        Test test;
        std::cout<<foobar<int>(test);
    }
    

    //edit was beim kopieren rausgeflutscht



  • ist nur einer drin, oder?



  • enum Typ { BaseTyp,MyClassTyp };
    
    class Style {};
    class Styler : private Style {
    
        private:
                long stylecode;
    
    };
    
    template<int N>
    struct Cool {
    
        Styler stylo;
        enum Look { hey = Cool<N-1>::hey ? (sizeof(stylo) == sizeof(long) ? 0xDEAD : 446) : 986};
    
    };
    
    template<>
    struct Cool<-10> {
    
        enum Look { hey = 5 };
    
    };
    
    class Interface {
    
       public:
                virtual Typ whoAmI(Typ i) = 0;
                virtual ~Interface() = 0;
    };
    
    class Base : public Interface {
    
        public:
                virtual Typ whoAmI(Typ i = BaseTyp)
                {
                    return i;
                }
    
                ~Base() { }
    };
    
    class MyClass : public Base {
    
        public:
                virtual Typ whoAmI(Typ i = MyClassTyp)
                {
                    return i;
                }
    
                ~MyClass() { }
    
    };
    
    int main()
    {
        Base base,*pbase = &base;
    
        cout << pbase->whoAmI() << endl;
    
        MyClass my;
        pbase = &my;
    
        cout << pbase->whoAmI() << endl;
    
        cout << Cool<10>::hey;
    }
    

    ...

    Compilieren ist verboten. _DU_ bist der Compiler 😃
    Edit: Verdammt! Habe paar Ablenkung vergessen, ist aber jetzt auch egal ...



  • @otze: Weiß leider nicht was der Fehler ist. Musste es durch den Compiler jagen und weiß trotzdem nicht wie man das behebt 🙂

    Es wird glaub ich mal langsam Zeit, dass ich mir "C++ Templates: A Complete Guide" hole, ist auch das nächste Buch, falls ich es mal schaffen sollte "More Excep-C++" anzufangen ...



  • camper schrieb:

    ist nur einer drin, oder?

    nur einer, denn der ist für leute dies nicht wissen schon schwer genug 😉



  • Hier gibts noch ne ganze Menge solcher Aufgaben.



  • ich lös mal auf:

    return Helper<T>::function<U>(t);
    

    das ist der Fehler. richtig ist es so:

    return Helper<T>::template function<U>(t);
    

    Das Problem ist, dass man nach dem zugriff auf einen templatetyp angeben muss, wenn danach ein weiteres template folgt, denn sonst wird das "<" pauschal als operator< interpretiert.

    Das gilt übrigens nicht nur für den operator:: sondern auch für die anderen zugriffsoperatoren, also "." und "->". Einige nichtstandardconforme Compiler spucken hier übrigens keinen Fehler aus, da sie das "template" nicht unbedingt benötigen.



  • otze schrieb:

    ich lös mal auf:

    return Helper<T>::function<U>(t);
    

    das ist der Fehler. richtig ist es so:

    return Helper<T>::template function<U>(t);
    

    Das Problem ist, dass man nach dem zugriff auf einen templatetyp angeben muss, wenn danach ein weiteres template folgt, denn sonst wird das "<" pauschal als operator< interpretiert.

    Ahh gut zu wissen.

    otze schrieb:

    Das gilt übrigens nicht nur für den operator:: sondern auch für die anderen zugriffsoperatoren, also "." und "->". Einige nichtstandardconforme Compiler spucken hier übrigens keinen Fehler aus, da sie das "template" nicht unbedingt benötigen.

    VC++ EE 🙄



  • Das wollte ich ja auch noch auflösen 🙂

    1.)

    (sizeof(stylo) == sizeof(long)
    

    sizeof(Styler) sollte es heißen, oder man macht stylo static. Das ganze drumherum, wie die Templates und Empty Base Optimization sollte natürlich nur Ablenken.

    2.)

    virtual ~Interface() = 0;
    

    Da denken vllt einige, dass dies korrekt sei, doch einen abstrakten Destruktor sollte man auch Implementieren, da die abgeleiteten Klassen ja den Destruktor der Basisklasse aufrufen müssen.

    //Wessen Compiler es mitmacht so:
    virtual ~Interface() = 0 { };
    //Besser
    virtual ~Interface() = 0;
    //...
    Interface::~Interface() { }
    

    3.)

    virtual Typ whoAmI(Typ i = BaseTyp)
    virtual Typ whoAmI(Typ i = MyClassTyp)
    //...
    Base base,*pbase = &base;
    cout << pbase->whoAmI() << endl;
    
    MyClass my;
    pbase = &my;
    
    cout << pbase->whoAmI() << endl;
    

    Ergibt zweimal 0 also BaseTyp. Das kommt daher, dass Defaultargumente statisch gebunden sind und virtuelle Funktion natürlich dynamisch.
    Und da der statische Typ von pbase Base* ist wird zweimal BaseTyp zurückgegeben.



  • Lust auf mehr kurze Knackige 🙂 ?



  • ja bitte 🙂



  • Ich finde compile-time Fehler viel uninteressanter als andere Fehler. Schliesslich ist es leicht zu wissen dass etwas nicht passt wenn einem der Compiler nen Fehler vorn Latz knallt.

    Ich würde also vorschlagen Code zu posten der fehlerfrei compiliert aber sicher nicht das tut was beabsichtigt war. Einfaches Beispiel:

    #include <string>
    
    class MyException
    {
    public:
    	MyException() {}
    	MyException(std::string const& str) : m_str(str) {}
    	MyException(MyException const& other)
    	try :
    		m_str(other.m_str)
    	{}
    	catch (...)
    	{}
    
    private:
        std::string m_str;
    };
    

    3 einfache Fragen:

    1. Was wollte der Programmierer hier erreichen?
    2. Warum geht es nicht und was passiert stattdessen?
    3. Wie lässt es sich fixen?


  • Kann leider momentan keine posten, da ich mein Netzteil vergessen habe und nun sparsam mit dem Akku umgehen, bis mein Netzteil wieder da ist 🙂

    Aber für die erste Frage von hustbaer reicht es dennoch 🙂

    hustbaer schrieb:

    1. Was wollte der Programmierer hier erreichen?

    Er wollte verhindern, das bei einer geflogenen Exception vom Typ MyException beim Kopieren des throw-Arguments keine weitere Exception rausfliegt.

    right ?



    1. er wollte erreichen, dass eine exception in der objektinitialisierungsliste gecatcht wird (aus dem vom vorposter genannten grund).
    2. die exception wird so oder so weitergeschmissen, da nicht garantiert werden kann, dass das Objekt in validem Zustand ist.
    3. z.B. das ganze in den Body des Konstruktors verlagern.


  • Alternativ kann man auch ein C-String mit fester Länge benutzen und so den Code ausnahmefrei bekommen.

    Folgender Code produziert 1 Fehler bei der Übersetzung. Bitte keinen Compiler benutzen, da die Fehlermeldungen in der Regel recht eindeutig sein sollte.

    #include <vector>
    #include <algorithm>
    using namespace std;
    
    namespace foo{
    	struct Data{
    		int a;
    	};
    
    	bool operator<(const Data&a, const Data&b){
    		return a.a < b.a;
    	}
    
    	void swap(Data&a, Data&b){
    		if(&a != &b){
    			a.a ^= b.a;
    			b.a ^= a.a;
    			a.a ^= b.a;
    		}
    	}
    }
    
    class MyContainer:private vector<foo::Data>{
    	typedef vector<foo::Data> super;
    public:
    	using super::iterator;
    	using super::const_iterator;
    	using super::begin;
    	using super::end;
    	using super::size;
    	using super::empty;
    };
    
    class MySuperContainer:public MyContainer{
    public:
    	void fast_sort(){
    		if(size() == 2){
    			iterator i = begin(), j = i;
    			++j;
    			if(*j < *i)
    				swap(*j, *i);
    		}else
    			sort(begin(), end());
    	}
    };
    


  • hmm, das einzige, was mir aufgefallen ist, ist, dass swap eigentlich im namespace foo ist, oder?
    naja, ich werds jetzt mal durchn compiler laufen lassen 😛

    Spoiler:

    edit: es lässt sich tatsächlich durch Ändern zu foo::swap(... lösen.
    was ich allerdings ursprünglich nicht gewusst (nur etwas geahnt) hatte, ist, dass vector auch eine methode swap besitzt (*referenz-nachguck*). Aber da diese Methode dazu da ist, die Inhalte eines vectors mit denen eines anderen zu tauschen, ist die hier wohl nicht sondelich hilfreich.



  • Heinzelotto schrieb:

    hmm, das einzige, was mir aufgefallen ist, ist, dass swap eigentlich im namespace foo ist, oder?

    Dank Koenig-Lookup dürfen solche Helferfunktionen auch im gleichen Namesraum wie der Typ selbst sein.



  • Ben04 schrieb:

    Heinzelotto schrieb:

    hmm, das einzige, was mir aufgefallen ist, ist, dass swap eigentlich im namespace foo ist, oder?

    Dank Koenig-Lookup dürfen solche Helferfunktionen auch im gleichen Namesraum wie der Typ selbst sein.

    Spoiler:

    ok, dann ergibt das Sinn. Der Compiler denkt, dass der User die methode vector::swap aufrufen will, die ja aber durch die private vererbung unzugänglich geworden ist (und die sowieso nicht von den übergabeparametern her passt). Durch absolute Qualifizierung der anderen Methode lässt sich das Problem aber umgehen.



  • Wie wird es geheilt?

    class MySuperContainer:public MyContainer{
    public:
        void fast_sort(){
            using ::std::swap; // <---
            if(size() == 2){
                iterator i = begin(), j = i;
                ++j;
                if(*j < *i)
                    swap(*j, *i);
            }else
                sort(begin(), end());
        }
    };
    


  • #include <iostream>
    #include <vector>
    #include <string>
    
    struct bar
    {
       int id;
       std::string name;
    };
    
    bar* find(std::vector<bar*> const &vec, std::string const &theName)
    {
       for(std::vector<bar*>::const_iterator it = vec.begin(); it != vec.end(); ++it)
       {
          if((*it)->name == theName)
          {
              return *it;
          }
       }
       return 0;
    }
    
    bool exists(std::vector<bar*> const &vec, std::string const &theName)
    {
       return find != 0;
    }
    
    void print(std::vector<bar*> const &vec)
    {
       for(std::vector<bar*>::const_iterator it = vec.begin(); it != vec.end(); ++it)
       {
          std::cout << (*it)->name << ", " << (*it)->id << std::endl;
       }
    }
    

    Der Code kompiliert, tut aber nicht das, was er eigentlich soll. So wie es hier ist, dürfte es reicht einfach zu finden sein...

    Felix


Anmelden zum Antworten