2016-05-13 13 views
0
template<class T, template<typename> class Seq> 
    class SequenceWithApply : public Seq<T*> 
    { 
    public: 
     // 0 arguments, any type of return value: 
     template<class R> 
     void apply(R (T::*f)()) { 
     iterator it = begin(); 
     while(it != end()) { 
      ((*it)->*f)(); 
      it++; } 
     } 

     // 1 argument, any type of return value: 
     template<class R, class A> 
     void apply(R(T::*f)(A), A a) { 
     iterator it = begin(); 
     while(it != end()) { 
      ((*it)->*f)(a); 
      it++; } 
     } 

     // 2 arguments, any type of return value: 
     template<class R, class A1, class A2> 
     void apply(R(T::*f)(A1, A2), 
       A1 a1, A2 a2) { 
     iterator it = begin(); 
     while(it != end()) { 
      ((*it)->*f)(a1, a2); 
      it++; 
     } 
     } 
    }; ///:~ 

//: C03:applyGromit2.cpp 
// Test applyMember.h 
#include "Gromit.h" 
#include "applyMember.h" 
#include <vector> 
#include <iostream> 
using namespace std; 
int main() { 
    SequenceWithApply<Gromit, vector> dogs; 
    for(int i = 0; i < 5; i++) 
    dogs.push_back(new Gromit(i)); 
    dogs.apply(&Gromit::speak, 1); 
    dogs.apply(&Gromit::eat, 2.0f); 
    dogs.apply(&Gromit::sleep, 'z', 3.0); 
    dogs.apply(&Gromit::sit); 
} ///:~ 

Ich habe nicht ganz verstanden, warum Compiler über iterator hier beschweren. Da dieser Code-Snippet implementiert eine Klasse SequenceWithApply basierend auf der Vorlage. In diesem Fall ist SequenceWithApply tatsächlich eine Basisklasse von vector. Iterator sollte in dieser Basisklasse sichtbar sein. Ich schätze wirklich, dass mir jemand helfen kann, dies herauszufinden.Vorlage Vererbung C++ Iterator

+0

Ich weiß, es gibt eine Betrogene irgendwo da draußen, aber 'Typname Seq :: iterator'. – chris

+0

Es ist nicht nur 'Iterator', sondern auch' begin() 'und' end() '. Ich habe keine Ahnung, warum das nicht funktioniert. :( – zhexuany

+0

Wenn ich einen Betrogenen finden könnte, würde es erklären, dass diese Namen nachgeschlagen werden, bevor das Template instanziiert wird, was bedeutet, dass es nicht wissen kann, welcher konkrete Basistyp nachzuschauen ist. – chris

Antwort

2

Der Compiler sucht bei der Suche in der ersten Phase nach iterator, bevor die Vorlage überhaupt instanziiert wird. Um zu wissen, von welchem ​​Typ die Klasse abgeleitet ist, muss die Vorlage instanziiert werden (so dass Seq<T*> ein tatsächlicher Typ ist). Daher findet der Compiler iterator in der Basisklasse noch nicht.

Sie können in zwei einfache Möglichkeiten, dies umgehen:

Einmalig:

typename Seq<T*>::iterator 

Ein Typ Alias ​​in der abgeleiteten Klasse:

using iterator = typename Seq<T*>::iterator; 

Alle diese eindeutig angeben zu welchem ​​Typ iterator gehört, in der zweiten Phase der Suche nachgeschlagen, wenn Seq und T bekannt sind. More on typename.

Sie können das gleiche tun für Ihre Funktionen:

Einmalig:

Seq<T*>::begin() 
this->begin() // if inside a member function 

Eine using-Deklaration:

using Seq<T*>::begin; 
+0

Vielen Dank für Ihren Beitrag. Wir müssen auch 'Seq ::' zu 'begin()' und 'end()' hinzufügen. Darüber hinaus gibt es eine weitere Frage zum Code. In der ersten Zeile dieses Snippets müssen Sie variadische Vorlagen hinzufügen. dh.'Vorlage Klasse Seq>' – zhexuany

+0

@zhexuany, 'std :: vector' hat mehr als einen Typparameter. Andere Standardcontainer haben unterschiedliche Nummern. Um ihre Verwendung einheitlicher zu unterstützen, können Sie eine beliebige Anzahl von Typparametern akzeptieren. – chris

+0

Ja. Deine Antwort ist großartig. Danke für deine freundliche Hilfe. – zhexuany

0

Das Buch Sie verwenden out sein kann Datum. Heutzutage hat sich C++ in Richtung freie Funktionen zur besseren Entkopplung bewegt.

Beispiel:

#include <vector> 
#include <iostream> 

// an example Gromit 
struct Gromit 
{ 
    Gromit(int index) : index(index) {}; 

    void speak(int i) { std::cout << name() << " speaking " << i << std::endl; } 
    void eat(float f) { std::cout << name() << " eating " << f << std::endl; } 
    void sleep(char c, double f) { std::cout << name() << " sleeping " << c << " " << f << std::endl; } 
    void sit() { std::cout << name() << " sitting" << std::endl; } 

private: 
    std::string name() const { 
     return "Gromit " + std::to_string(index); 
    } 
    int index; 
}; 

// apply some function object to each item in a container  
template<class Container, class F> 
void apply(Container& container, F f) 
{ 
    for (const auto& p : container) 
    { 
     f(p); 
    } 

} 

int main() { 
    std::vector<std::unique_ptr<Gromit>> dogs; 
    for(int i = 0; i < 5; i++) 
     dogs.emplace_back(new Gromit(i)); 

    using namespace std::placeholders; 

    // apply dog.speak(1) to each dog in dogs...   
    apply(dogs, std::bind(&Gromit::speak, _1, 1)); 

    // dog.eat(2.0f) for each dog in dogs... 
    apply(dogs, std::bind(&Gromit::eat, _1, 2.0f)); 

    // ...etc 
    apply(dogs, std::bind(&Gromit::sleep, _1, 'z', 3.0)); 
    apply(dogs, std::bind(&Gromit::sit, _1)); 
} 

erwartete Ausgabe:

Gromit 0 speaking 1 
Gromit 1 speaking 1 
Gromit 2 speaking 1 
Gromit 3 speaking 1 
Gromit 4 speaking 1 
Gromit 0 eating 2 
Gromit 1 eating 2 
Gromit 2 eating 2 
Gromit 3 eating 2 
Gromit 4 eating 2 
Gromit 0 sleeping z 3 
Gromit 1 sleeping z 3 
Gromit 2 sleeping z 3 
Gromit 3 sleeping z 3 
Gromit 4 sleeping z 3 
Gromit 0 sitting 
Gromit 1 sitting 
Gromit 2 sitting 
Gromit 3 sitting 
Gromit 4 sitting