2010-03-22 8 views
5

Teniendo en cuenta esta clase:¿Puedo escribir functors usando una estructura anidada privada?

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

La idea aquí es que fooList pueden ser indexados por cualquiera key1 o key2 de la struct Foo. Intento escribir functors para pasar a std::find_if para poder buscar elementos en fooList con cada tecla. Pero no puedo hacer que compilen porque Foo es privado dentro de la clase (no es parte de la interfaz de C). ¿Hay alguna manera de hacerlo sin exponer Foo al resto del mundo?

He aquí un ejemplo de código que no se compilará porque Foo es privado dentro de mi clase:

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; 
    } 
}; 

Respuesta

2

me gustaría hacer algo como esto.

Cabecera:

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

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

    std::vector<Foo> fooList; 
}; 

Fuente:

// 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; 
}; 

Uso:

// 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. 
} 

Una especie de ...

+0

+1, me olvidé de simplemente anunciar los funtores como estructuras anidadas. He corregido un error tipográfico (copiar y pegar-o?) Para ti también. –

+0

@Kristo: copiar y pegar-o? usted apuesta-o! ;) –

1

Se podría hacer que el funtor un amigo de C.

2

Sí. Haga del functor otro miembro de C y encapsule std::find_if detrás de un método de C.

siguiente es un ejemplo:

#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 sintaxis es bastante barroco, pero podría convertirse fooList in a un boost::multi_index_container indexado en key1 y key2.

+0

+1, por todas las veces que sugerí multi_index y nunca me subieron;) – pmr

0

Si no necesita su estructura dentro de su encabezado, también puede usar espacios de nombres no nombrados en su archivo de implementación para hacer que las definiciones y declaraciones sean locales para la unidad de compilación (con estática es la alternativa C-static).

Esto le deja con un encabezado de limpiador que no queda oscurecido por los detalles de implementación.

+0

Creo que 'Foo' todavía necesita ser declarado en el encabezado porque' fooList' depende de él. –

+0

@Kristo: Ciertamente, pero la pregunta era sobre el functor, no sobre la estructura misma.La verdadera pregunta es si la estructura Foo es realmente solo un detalle de implementación o si debe proporcionarse fuera de su clase. – pmr

0

Podría usar el Pimpl Idiom para ocultar la sección privada de C dentro de otra clase. Dado que todo en CImpl puede ser público de forma segura, debería poder hacer lo que quiera con Foo allí.

Cuestiones relacionadas