2010-03-22 4 views
5

Dato questa classe:Posso scrivere funtori usando una struttura nidificata privata?

class C 
{ 
    private: 
     struct Foo 
     { 
      int key1, key2, value; 
     }; 
     std::vector<Foo> fooList; 
}; 

L'idea è che fooList può essere indicizzato da uno o key1key2 della struct Foo. Sto cercando di scrivere i functor per passare a std::find_if in modo da poter cercare gli elementi in fooList da ogni chiave. Ma non riesco a farli compilare perché Foo è privato all'interno della classe (non fa parte dell'interfaccia di C). C'è un modo per farlo senza esporre Foo al resto del mondo?

Ecco un esempio di codice che non viene compilato perché Foo è privato all'interno della mia classe:

struct MatchKey1 : public std::unary_function<Foo, bool> 
{ 
    int key; 
    MatchKey1(int k) : key(k) {} 
    bool operator()(const Foo& elem) const 
    { 
     return key == elem.key1; 
    } 
}; 

risposta

2

mi piacerebbe fare qualcosa di simile.

Intestazione:

class C 
{ 
private: 
    struct Foo 
    { 
     int index; 
     Bar bar; 
    }; 

    // Predicates used to find Notification instances. 
    struct EqualIndex; 
    struct EqualBar; 

    std::vector<Foo> fooList; 
}; 

Fonte:

// Predicate for finding a Foo instance by index. 
struct C::EqualIndex : std::unary_function<C::Foo, bool> 
{ 
    EqualIndex(int index) : index(index) { } 
    bool operator()(const C::Foo& foo) const { return foo.index == index; } 
    const int index; 
}; 

// Predicate for finding a Foo instance by Bar. 
struct C::EqualBar : std::unary_function<C::Foo, bool> 
{ 
    EqualBar(const Bar& bar) : bar(bar) { } 
    bool operator()(const C::Foo& foo) const { return foo.bar == bar; } 
    const Bar& bar; 
}; 

Usage:

// Find the element containing the Bar instance someBar. 
std::vector<Foo>::iterator it = std::find_if(fooList.begin(), 
              fooList.end(), 
              EqualBar(someBar)); 

if (it != fooList.end()) 
{ 
    // Found it. 
} 

Sorta di ...

+0

+1, ho dimenticato semplicemente in avanti dichiarando che anche i funtori sono strutture annidate. Ho corretto un refuso (copy-and-paste-o?) Anche per te. –

+0

@ Kristo: copia-e-incolla-o? hai scommesso-o! ;) –

1

Si potrebbe fare il funtore amico di C.

2

Sì. Rendere il functor un altro membro di C e incapsulare std::find_if dietro un metodo di C.

seguente è un esempio:

#include "stdafx.h" 
#include <vector> 
#include <cassert> 
#include <algorithm> 
#include <iostream> 

class C 
{ 
    private: 
     struct Foo 
     { 
      int key1, key2, value; 
     }; 

     std::vector<Foo> fooList; 

    struct Finder 
    { 
    private: 
     int key1, key2; 

    public: 
     Finder(int k1, int k2) 
     { 
     key1 = k1; 
     key2 = k2; 
     } 

     bool operator()(Foo const& foo) const 
     { 
     return foo.key1 == key1 || foo.key2 == key2; 
     } 
    }; 

public: 
    C() 
    { 
    Foo foo1, foo2; 
    foo1.key1 = 5; 
    foo1.key2 = 6; 
    foo1.value = 1; 
    foo2.key1 = 7; 
    foo2.key2 = 8; 
    foo2.value = 10; 

    fooList.insert(fooList.begin(), foo1); 
    fooList.insert(fooList.begin(), foo2); 
    } 

    int Find(int key1, int key2) 
    { 
    return std::find_if(fooList.begin(), fooList.end(), Finder(key1, key2))->value; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    C c; 

    std::cout << c.Find(5, 3) << std::endl; 
    std::cout << c.Find(3, 6) << std::endl; 
    std::cout << c.Find(7, 3) << std::endl; 
    std::cout << c.Find(3, 8) << std::endl; 

    return 0; 
} 
1

La sintassi è piuttosto barocco, ma ho potuto girare fooList in a boost::multi_index_container indicizzato su key1 e key2.

+0

+1, per tutte le volte che ho suggerito multi_index e mai upvoted;) – pmr

0

Se non si ha bisogno della propria struttura nell'intestazione, è possibile utilizzare anche spazi dei nomi senza nome nel file di implementazione per rendere le definizioni e le dichiarazioni locali all'unità di compilazione (con statico che rappresenta l'alternativa C-like static).

Questo ti lascia con un'intestazione più pulita che non è oscurata dai dettagli di implementazione.

+0

Penso che 'Foo' debba ancora essere dichiarato nell'intestazione perché' fooList' dipende da esso. –

+0

@Kristo: Certamente, ma la domanda riguardava il funtore e non la struttura stessa.La vera domanda è se la struct Foo è in realtà solo un dettaglio di implementazione o se dovrebbe essere fornita al di fuori della tua classe. – pmr

0

Potrei usare lo Pimpl Idiom per nascondere la sezione privata di C all'interno di un'altra classe. Poiché tutto in CImpl può essere sicuro in pubblico, dovrei essere in grado di fare tutto ciò che voglio con Foo lì.