2011-08-24 4 views
6

C'è un modo per fare std :: set_intersection su due diversi tipi di set?set_intersection per due diversi tipi di set

ho due set:

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

sono in grado di definire alcuni comparatore per loro che controlla se X1 e X2 sono uguali.

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

Ora, provo a fare una serie di intersezione su quei due insiemi:

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()); 

Purtroppo, non posso forzare questo codice funzioni. Non sono nemmeno sicuro che sia possibile, ma dal description di set_intersection so che posso usare due diversi iteratori.

Ho provato a cercare alcuni esempi di codice che fanno ciò che voglio, ma non ne ho trovato nessuno? Qualcuno potrebbe presentarmi un esempio di codice funzionante per il mio problema?

Aggiornamento: l'errore è:

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

Grazie in anticipo!

+0

"Sfortunatamente, non posso forzare questo codice a funzionare." Quali errori del compilatore ottieni? –

+1

Il tuo comparatore di campioni non fa la cosa giusta. Deve essere un numero inferiore a, imponendo un rigoroso ordine debole sugli elementi comparati. – tokage

+0

Hai provato a fornire un operatore booleano

risposta

3

Il commento di PlasmaHH è probabilmente il problema.

Il modo in cui funziona come il lavoro set_intersection è che prima fanno: a < b e poi b < a

Come risultato ample_comparer deve essere in grado di confrontare entrambi i modi:

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

Il seguente in realtà non fare niente di sensato - ma non compilare in modo pulito:

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

Non funzionerà poiché entrambi gli ingressi devono essere assegnabili al tipo di iteratore di uscita. È possibile aggiungere alcuni operatori di conversione impliciti a X1, X2 che converte tra di loro per farlo funzionare.

+0

Per set_intersection l'intervallo di output deve solo consentire le conversioni da uno degli input (anche se non è specificato quale). Qualcosa come set_union o set_difference richiede conversioni da entrambi i tipi. –

2

Non penso sia possibile così com'è, (almeno senza conversione definita dall'utente). Dalla sezione "Requisiti sui tipi" in documentation: InputIterator1 and InputIterator2 have the same value type.

+0

Grazie per la risposta e grazie per aver indicato la soluzione nei documenti – matekm

+0

Perché la funzione consentirebbe due diversi tipi di iteratore di input se il valore fosse identico? –

0

Prima di tutto secondo il set_intersect docs ione sta usando un operatore <. E in secondo luogo si può fare una terza struct che estrae dal tipo i campi che si utilizzeranno per fare confrontare

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){ 
... } ) 

Si può andare su questa strada e di creare un wrapper personalizzato che può fare nulla a meno che i due tipi possono confrontare

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

Qualcosa del genere. Non l'ho testato e non verrà compilato, ma ottieni il punto.Forse qualcosa di simile è nascosto qualcosa da qualche parte nelle librerie STL

Edit: Btw penso che tu possa usare un qualche tipo di variante (boost :: variant o std :: variant) Penso che faccia già questo ...