2011-08-24 24 views
6

¿Hay alguna manera de hacer std :: set_intersection en dos tipos diferentes de conjuntos?set_intersection para dos tipos diferentes de conjuntos

I tienen dos conjuntos:

std::set<X1> l_set1; 
std::set<X2> l_set2; 

soy capaz de definir algunos comparador para ellos que comprueba si X1 y X2 son iguales.

struct sample_comparer 
{ 
    bool operator()(const &X1 p_left, const &X2 p_right) 
    { 
     return p_left == p_right; 
    } 
}; 

Ahora, trato de hacer un conjunto intersección de estos dos conjuntos:

std::set<X1> l_intersect; 
std::set_intersection(l_set1.begin(), l_set1.end(), l_set2.begin(), l_set2.end(), 
         std::inserter(l_intersect, l_intersect.begin()), sample_comparer()); 

Por desgracia, no puedo obligar a que este código funcione. Ni siquiera estoy seguro de si esto es posible, pero desde el description de set_intersection sé que puedo usar dos iteradores diferentes.

He intentado buscar algunas muestras de código que hacen lo que quiero, pero no encontré ninguna? ¿Podría alguien presentarme una muestra de código de trabajo para mi problema?

Actualización: el error es:

error: stl_function.h:227: no match for 'operator<' in '__x < __y'

Gracias de antemano!

+0

"Desafortunadamente, no puedo forzar este código para que funcione". ¿Qué errores de compilación recibe? –

+1

Su comparador de muestra no hace lo correcto. Necesita ser menos que, imponer un orden estricto y débil a los elementos comparados. – tokage

+0

¿Intentó proporcionar un operador de bool

Respuesta

3

El comentario de PlasmaHH es probablemente el problema.

La manera en que funciona como el trabajo set_intersection se hacen por primera vez: a < b y luego b < a

Como resultado ample_comparer tiene que ser capaz de comparar dos formas:

struct sample_comparer 
{ 
    bool operator()(const &X1 p_left, const &X2 p_right) 
    { 
     return p_left == p_right; 
    } 
    bool operator()(const &X2 p_left, const &X1 p_right) 
    { 
     return p_left == p_right; 
    } 
}; 

El siguiente en realidad no hacer cualquier cosa sensata, pero compila limpiamente:

struct A 
{ 
    struct Compare { bool operator() (A const &, A const &) { return false;} }; 
}; 

struct B 
{ 
    struct Compare { bool operator() (B const &, B const &) { return false; } }; 
}; 

typedef std::set<A, A::Compare> S1; 
typedef std::set<B, B::Compare> S2; 

class IntersectionCompare 
{ 
public: 
    bool operator()(S1::value_type, S2::value_type) { return false; } 
    bool operator()(S2::value_type, S1::value_type) { return false; } 
}; 

void bar (S1 & s1, S2 & s2) 
{ 
    S1 result; 
    std::set_intersection (s1.begin() 
     , s1.end() 
     , s2.begin() 
     , s2.end() 
     , std :: insert_iterator<S1> (result, result.end()) 
     , IntersectionCompare()); 
} 
4

No funcionará, ya que ambas entradas deben poder asignarse al tipo de iterador de salida. Puede agregar algunos operadores de conversión implícitos a X1, X2, que los convierte entre ellos para que funcionen.

+0

Para set_intersection el rango de salida solo necesita permitir conversiones de uno de las entradas (aunque no se especifica cuál). Algo como set_union o set_difference requiere conversiones de ambos tipos. –

2

No creo que sea posible tal como es, (al menos sin conversión definida por el usuario). De la sección "Requisitos sobre tipos" en documentation: InputIterator1 and InputIterator2 have the same value type.

+0

Gracias por la respuesta y gracias por señalar la solución en los documentos – matekm

+0

¿Por qué la función permite dos tipos diferentes de iteradores de entrada si el valor debe ser idéntico? –

0

En primer lugar, de acuerdo con los documentos set_intersect ion está utilizando un operador <. Y en segundo lugar se puede hacer una tercera estructura que va a extraer del tipo de los campos que va a utilizar para hacer comparan

std::set<X1> l_set1; 
std::set<X2> l_set2; 
struct XCompare 
{   
    int value; 
    XCompare(const X1& x) 
    { 
     value = x.value; 
    } 

    XCompare(const X2& x) 
    { 
     value = x.value; 
    } 
} 

std::set_intersection(...,...,[](const XCompare& c1, const XCompare& c2){ 
... } ) 

Puede ir por este camino y crear un envoltorio personalizado que se puede hacer nada a menos que los dos tipos pueden comparar

template<typename T1, typename T2> 
struct ValueWrapper 
{ 
    T1 const* v1 = nullptr; 
    T2 const* v2 = nullptr; 

    ValueWrapper(const T1& value) 
    { 
     v1 = &value; 
    } 

    ValueWrapper(const T2& value) 
    { 
     v2 = &value; 
    } 

    bool operator<(const ValueWrapper& other) 
    { 
     if (v1 != nullptr) 
     { 
      if (other.v1 != nullptr) 
      { 
       return *v1 < *(other.v2) 
      } 

... }}

template<typename T1, typename T2> 
struct ValueWrapperComparator 
{ 
    bool operator()(ValueWrapper<T1,T2> v1, ValueWrapper<T1,T2> v2) 
    { 
     return v1 < v2; 
    } 
} 

Algo por el estilo. No lo probé y no compilará, pero entiendes el punto.Tal vez algo similar se esconde algo similar en alguna parte de las bibliotecas STL

Editar: Por cierto, creo que puedes usar algún tipo de variante (boost :: variant o std :: variant) Creo que ya lo hace ...

Cuestiones relacionadas