2017-09-04 4 views
1

Ich glaube, das ist ein Beispiel für das seltsam wiederkehrende Vorlagenmuster. Es scheint mir, dass dies kompilieren sollte, tut es aber nicht. Dies ist mit Clang in Xcode 8.3.Warum kompiliert dieses merkwürdig wiederkehrende Vorlagenmusterbeispiel nicht?

template<class T> 
class Fungeable 
{ 
public: 
    virtual ~Fungeable() {} 
    virtual bool funge(const Fungeable<T>& inFungeable) const = 0; 
}; 

class Blarg : public Fungeable<Blarg> 
{ 
public: 
    virtual bool funge(const Blarg& inFungeable) const override { return true; } 
}; 

int main(int argc, const char * argv[]) { 
    Blarg b; 
    Blarg x; 
    return static_cast<int>(b.funge(x)); 
} 

Es scheint, wie das funktionieren sollte, weil Blarg ein Fungeable ist. Aber ich habe den Fehler 'funge' marked 'override' but does not override any member functions

Wenn ich die Unterschrift von Blarg::funge() ändern, um eine Fungeable<Blarg> so nehmen:

class Blarg : public Fungeable<Blarg> 
{ 
public: 
    virtual bool funge(const Fungeable<Blarg>& inFungeable) const override { return true; } 
}; 

Dann kompiliert.

Sollte nicht die erste Version funktionieren, da Blarg definitionsgemäß eine Fungeable<Blarg> ist?

+1

"seit Blarg ist per definitionem ein Fungeable " Jeder 'Blarg' ein' Fungeable 'ist aber nicht jeder' Fungeable 'ist ein' Blarg'. – tkausl

Antwort

3

Co-variante Parametertypen haben nicht, nie, und werden höchstwahrscheinlich nie in C++ funktionieren. Sie können denken, dass Ihr Beispiel "offensichtlich" sicher ist. Aber die Funktion ist im Allgemeinen nicht sicher und das Hinzufügen von Unterstützung für solch einen kleinen Anwendungsfall wird nicht passieren.

Zur Veranschaulichung:

struct food {}; 
struct grass : food {}; 

struct animal { 
    virtual void eat(food&) = 0; 
}; 

void feed(animal& a) { 
    a.eat(grass{}); 
} 

So weit so gut. Nun lassen Sie uns mehr auf die Hierarchie hinzuzufügen, haben wir Parametertypen zusammen Variante unter der Annahme:

struct meat : food {}; 

struct lion : animal { 
    void eat(meat&) {/*...*} 
}; 

Was passiert, wenn ich ein lion Objekt feed passieren? Es kann nicht grass als Essen behandeln, aber es ist-aanimal. Dies bricht das Liskov-Substitutionsprinzip.

+1

In Ihrem ersten Satz meinen Sie "Parameter" statt "Rückkehr"? –

+0

@MatthewJamesBriggs - Whoops. Ja, mache ich. Co-variante Rückgabetypen werden unterstützt, daher ein großer Fehler meinerseits. – StoryTeller

Verwandte Themen