2016-07-23 36 views
0

Wort.Std :: Set. Benutzerdefinierte Reihe von Sets

Ich habe eine Struktur, ein einzelnes Feld enthalten, die ich setzen würde gerne für den Vergleich und die Gleichwertigkeit und andere Bereiche als Metadaten zu verwenden:

struct read_tag{ 
    unsigned int read_id; // want std::set to use this 
    int offset;   // metadata 
    bool orientation;  // metadata 
}; 

Ich habe einen Funktor den Job zu erledigen:

struct read_tag_compare { 
    bool operator() (const read_tag &a, const read_tag &b) const { 
     return a.read_id > b.read_id 
    } 
}; 

und decl. der erforderliche Satz als

std::set<read_tag, read_tag_compare> block; 

Alles bis jetzt kompiliert. Das Problem ist unten:

Wie mache ich einen Satz, der std::set<read_tag, read_tag_compare> enthält. Ich möchte etwas wie das:

std::set< std::set<read_tag, read_tag_compare> > blocks; 
blocks.insert(a_block); // comp error 

Aber das gibt mir einen sehr großen und schwer zu entziffern Fehler.

Ich dachte, es würde rekursiv überprüfen, wie die inneren Mengen verglichen werden und diese auf die äußeren Mengen erweitern. Alles, was man tun musste, ist den Komparator für den innersten Satz zu definieren.

Zum Beispiel

std::set<std:set<unsigned int>> set_o_sets; 

funktioniert gut, ohne mich wie zu definieren, die vergleichen std::set<unsigned int>

Jede Hilfe ist mucho geschätzt: D

+0

Nein, weil ich nur ein 'std :: set ' in 'Blöcken' durch die Äquivalenz definiert haben möchte. –

+0

Es ist mir egal, wenn die Metadaten aus den beiden Sets nicht gleichwertig sind. Because, wenn zwei Sätze alle die gleichen 'read_tag ​​'in Bezug auf' read_tag ​​enthalten.read_id' Die Metadaten sind nicht in einem numerischen Sinn äquivalent, aber die gleiche Information kann später abgeleitet werden. So kann ich entweder einen der beiden Sätze nehmen, aber ich will nicht beide –

Antwort

3

Der < -Vergleich std::set verwendet std::lexicographical_compare ohne Vergleich, d. H. Es wird nur auf den Elementtyp < weitergeleitet. (Dies ist eine Einschränkung der Standardbibliothek, da diese für alle Container definiert ist, nicht nur für die sortierten assoziativen.) Was Sie also brauchen, ist ein benutzerdefinierter Komparator für Sätze von Sätzen, der die korrekte Überladung des lexikografischen Vergleichs verwendet:

using read_tag_set = std::set<read_tag, read_tag_compare>; 

struct read_tag_set_compare { 
    bool operator()(const read_tag_set &a, const read_tag_set &b) const noexcept { 
     return std::lexicographical_compare(a.begin(), a.end(), 
              b.begin(), b.end(), a.key_comp()); 
     //              ^^^^^^^^^^^^ 
    } 
}; 

Jetzt verwenden: std::set<read_tag_set, read_tag_set_compare>


Der Code zeigt, warum ist es nicht offensichtlich, dass die „fix“ der bestellten assoziativen Container, die dies machen würde „einfach funktionieren“: Wenn die Behälter benutzerdefinierte verwenden, Stateful Prädikate, dann ist es im Allgemeinen nicht garantiert, dass die Mitglieder von zwei verschiedenen Containern tatsächlich mit einem ano verglichen werden können es überhaupt. Alles, was Sie wissen, ist, dass die Elemente innerhalb eines Containers mit dem Komparator dieses Containers vergleichbar sind. Wenn Sie also einen benutzerdefinierten Vergleicher verwenden, sollten Sie auch explizit angeben, wie sich zwei verschiedene Container verhalten, und Sie erklären explizit, dass es sinnvoll ist, zwei Container zu vergleichen.

+0

[Demo] (http://melpon.org/wandbox/permlink/52qhsJZVO8FhIQXL) –

+0

Sir, Sie sind wirklich ein Gott unter den Menschen. Vielen Dank! Also wird 'a.key_comp()' die Verwendung meines 'read_tag_compare'-Funktors "veranlassen", den Vergleich zwischen zwei 'std :: set ' s durchzuführen? –

+0

Sie haben das Problem der Benutzerdefinition mit Benutzerdefinition gut erklärt. Typen, die keinen Vergleich ergeben können; anstatt es als zu zweideutig wie "Schuh" zu parieren, bevor er durch die Down-Abstimmung erschreckt wurde ... oh SO –

0

es mit meinem g ohne Fehler kompiliert ++ - 5.3 .1 ubuntu ..

#include<set> 
#include<iostream> 
using namespace std; 

struct read_tag{ 
    unsigned int read_id; // want std::set to use this 
    int offset;   // metadata 
    bool orientation;  // metadata 
}; 
struct read_tag_compare { 
    bool operator() (const read_tag &a, const read_tag &b) const { 
     return a.read_id > b.read_id; 
    } 
}; 
struct read_compare { 
bool operator() (const set<read_tag, read_tag_compare> &a, const  set<read_tag, read_tag_compare> &b) const { 
    return true; 
} 
}; 

int main() 
{ 
    set<read_tag, read_tag_compare> block; 
    set<set<read_tag, read_tag_compare>, read_compare> blocks; 
    blocks.insert(block) 
} 

Oben war, was ich kompilierte.

+1

Kannst du das zeigen? –

+0

Ich habe einfach Ihren Code kopiert und eingefügt. Es kompiliert gut ohne Fehler. Wie kann ich es dir zeigen? – Parker

+0

In der Tat, ja, das kompiliert, es ist blocks.insert(), dass Fehler. –