2009-05-13 5 views
4

Verwirrende Titel, hoffentlich einige Code klären:Aufruf von Elementfunktionen von Elementen eines Containers mit for_each?

struct MyNestedType { 
    void func(); 
}; 

struct MyType { 
    MyNestedType* nested; 
} 

std::vector<MyType> vec; 

// ... populate vec 

// I want something approximating this line, but that doesn't use made-up C++! 
std::for_each(vec.begin(), vec.end(), std::mem_fun_ref(&MyType::nested->func)); 

Also im Grunde möchte ich auf jedem Element des Behälters, ein Verfahren nennen, aber es ist nicht wirklich ein Verfahren des Typs, dann ist es eine Methode auf einem enthaltenen Typ ... Ich weiß, ich könnte ein Funktionsobjekt schreiben, um den Anruf weiterzuleiten, aber es gibt ein paar Methoden, die ich anrufen möchte, und das wird unordentlich.

Irgendwelche Ideen?

Antwort

3

können Sie solche Funktors verwenden

template <typename T, T* MyType::* TMember, void (T::* TNestedMember)() > 
struct Caller { 
    Caller() { 
    } 

    template <typename TObject> 
    void operator()(TObject object) { 
     (object.*TMember->*TNestedMember)(); 
    } 
}; 

Um Ihr Problem zu lösen

struct MyNestedType { 
    MyNestedType(int a): 
     a_(a){ 
    } 
    void func() { 
     std::cout << "MyNestedType::func " << a_ << std::endl; 
    } 
    void foo() { 
     std::cout << "MyNestedType::foo " << a_ << std::endl; 
    } 
    int a_; 
}; 
struct MyType { 
    MyNestedType* nested; 
}; 

int main() 
{ 
    std::vector<MyType> vec; 

    std::auto_ptr<MyNestedType> nt1(new MyNestedType(2)); 
    std::auto_ptr<MyNestedType> nt2(new MyNestedType(5)); 
    MyType t1 = {nt1.get()}; 
    MyType t2 = {nt2.get()}; 

    vec.push_back(t1); 
    vec.push_back(t2); 

    std::for_each(vec.begin(), vec.end(), 
        Caller<MyNestedType, &MyType::nested, &MyNestedType::func>()); 
    std::for_each(vec.begin(), vec.end(), 
        Caller<MyNestedType, &MyType::nested, &MyNestedType::foo>()); 
} 
+0

Brilliant, das ist genau die Antwort, auf die ich gehofft hatte, obwohl einige der anderen Kommentare mich denken ließen, dass ich vielleicht nach dem Falschen suchte;) –

+0

Gute Antwort, du hast geahnt, dass Ben sowohl die Methode als auch das Nested parametrisieren wollte Mitglied Objekt, obwohl es nicht angegeben wurde. – veefu

+0

Keine Notwendigkeit, snarky zu sein. Wäre es klarer gewesen, wenn ich "& MyType :: nested :: MyNestedType :: func" anstelle von "& MyType :: nested-> func" geschrieben hätte? Ich dachte, ich würde die Grenzen von Pseudo-C++ verschieben, wie es war! –

6

Warum verwenden Sie nicht einfach eine einfache For-Schleife?

for(vector<MyType>::iterator i = vec.begin(); i != vec.end(); ++i) 
    i->nested->func(); 

Alternativ können Sie Lambda-Ausdrücke oder boost :: foreach

FOREACH(MyType x, vec) 
    x.nested->func(); 

Sie können Ihre oben Ausdruck mit Bindemitteln und mem_funs, aber das wird kommen sehr chaotisch und verwirrend verwenden bauen! Es hat keinen Vorteil, alles in eine std :: foreach-Zeile zu schreiben.

+1

Natürlich gibt es einen Vorteil! Es wird mich wirklich sehr schlau fühlen lassen! Punkt genommen, obwohl. Vielleicht lasse ich es einfach als for-Schleife, wie ich es jetzt habe. –

+0

natürlich, boost foreach war mein erster Gedanke, als ich mir vorstellte, wie unordentlich es mit boost :: bind :) werden würde +1 +1 –

2

Vielleicht könnten Sie func() in struct MyType add():

void func(...) { 
    nested->func(...); 
} 

diese Weise werden Sie keine separaten Adapter Funktors haben, sondern eine Ansammlung innerhalb Wrapper-Typ, das heißt ganz normale OOP-Technik.

+0

Ein ruddy guter Punkt. Ich habe eine andere Antwort akzeptiert, da sie die Frage beantwortet, aber ich habe diese Antwort bewertet, da es der Ratschlag ist, den ich wahrscheinlich nehmen werde! –

2

Ja, es ist möglich, boost::bind dafür zu verwenden, aber es wird unordentlich. Bitte verwenden Sie @ Darios Schub für-jeden Weg, aber hier ist die boost::bind eine aus Gründen der Vollständigkeit

std::for_each(vec.begin(), vec.end(), 
    boost::bind(&MyNestedType::func, boost::bind(&MyType::nested, _1))); 

Wie auch immer, wie es geschieht, bekommen wir nicht einmal einen schönen Einzeiler mit diesem :)