Le premier commentaire (bien voté) de la réponse acceptée se plaint du manque d'opérateur pour les opérations std set existantes.
D'une part, je comprends le manque de tels opérateurs dans la bibliothèque standard. D'autre part, il est facile de les ajouter (pour le plaisir personnel) si désiré. J'ai surchargé
operator *()
pour l'intersection des ensembles
operator +()
pour l'union des ensembles.
Exemple test-set-ops.cc
:
#include
#include
#include
template , class ALLOC = std::allocator >
std::set operator * (
const std::set &s1, const std::set &s2)
{
std::set s;
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
std::inserter(s, s.begin()));
return s;
}
template , class ALLOC = std::allocator >
std::set operator + (
const std::set &s1, const std::set &s2)
{
std::set s;
std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(),
std::inserter(s, s.begin()));
return s;
}
// code d'exemple pour les tester :
#include
using namespace std;
template
ostream& operator << (ostream &out, const set &values)
{
const char *sep = " ";
for (const T &value : values) {
out << sep << value; sep = ", ";
}
return out;
}
int main()
{
set s1 { 1, 2, 3, 4 };
cout << "s1: {" << s1 << " }" << endl;
set s2 { 0, 1, 3, 6 };
cout << "s2: {" << s2 << " }" << endl;
cout << "I: {" << s1 * s2 << " }" << endl;
cout << "U: {" << s1 + s2 << " }" << endl;
return 0;
}
Compilé et testé :
$ g++ -std=c++11 -o test-set-ops test-set-ops.cc
$ ./test-set-ops
s1: { 1, 2, 3, 4 }
s2: { 0, 1, 3, 6 }
I: { 1, 3 }
U: { 0, 1, 2, 3, 4, 6 }
$
Ce que je n'aime pas, c'est la copie des valeurs de retour dans les opérateurs. Peut-être que cela pourrait être résolu en utilisant une assignation par déplacement, mais cela dépasse encore mes compétences.
En raison de mes connaissances limitées concernant ces "nouvelles et élégantes" sémantiques de déplacement, je m'inquiétais des retours des opérateurs qui pourraient entraîner des copies des ensembles retournés. Olaf Dietsche a souligné que ces préoccupations étaient inutiles car std::set
est déjà équipé d'un constructeur/d'une affectation par déplacement.
Bien que je lui aie fait confiance, je réfléchissais à la manière de le vérifier (pour quelque chose de "convaincant pour moi-même"). En fait, c'est assez facile. Comme les modèles doivent être fournis dans le code source, vous pouvez simplement avancer pas à pas avec le débogueur. Ainsi, j'ai placé un point d'arrêt juste avant le return s;
de l'opérateur *() et j'ai procédé étape par étape, ce qui m'a immédiatement mené à std::set::set(_myt&& _Right)
: et voilà - le constructeur de déplacement. Merci, Olaf, pour l'(ma) illumination.
Pour des raisons de complétude, j'ai également implémenté les opérateurs d'affectation correspondants
operator *=()
pour l'intersection "destructive" des ensembles
operator +=()
pour l'union "destructive" des ensembles.
Exemple test-set-assign-ops.cc
:
#include
#include
template , class ALLOC = std::allocator >
std::set& operator *= (
std::set &s1, const std::set &s2)
{
auto iter1 = s1.begin();
for (auto iter2 = s2.begin(); iter1 != s1.end() && iter2 != s2.end();) {
if (*iter1 < *iter2) iter1 = s1.erase(iter1);
else {
if (!(*iter2 < *iter1)) ++iter1;
++iter2;
}
}
while (iter1 != s1.end()) iter1 = s1.erase(iter1);
return s1;
}
template , class ALLOC = std::allocator >
std::set& operator += (
std::set &s1, const std::set &s2)
{
s1.insert(s2.begin(), s2.end());
return s1;
}
// code d'exemple pour les tester :
#include
using namespace std;
template
ostream& operator << (ostream &out, const set &values)
{
const char *sep = " ";
for (const T &value : values) {
out << sep << value; sep = ", ";
}
return out;
}
int main()
{
set s1 { 1, 2, 3, 4 };
cout << "s1: {" << s1 << " }" << endl;
set s2 { 0, 1, 3, 6 };
cout << "s2: {" << s2 << " }" << endl;
set s1I = s1;
s1I *= s2;
cout << "s1I: {" << s1I << " }" << endl;
set s2I = s2;
s2I *= s1;
cout << "s2I: {" << s2I << " }" << endl;
set s1U = s1;
s1U += s2;
cout << "s1U: {" << s1U << " }" << endl;
set s2U = s2;
s2U += s1;
cout << "s2U: {" << s2U << " }" << endl;
return 0;
}
Compilé et testé :
$ g++ -std=c++11 -o test-set-assign-ops test-set-assign-ops.cc
$ ./test-set-assign-ops
s1: { 1, 2, 3, 4 }
s2: { 0, 1, 3, 6 }
s1I: { 1, 3 }
s2I: { 1, 3 }
s1U: { 0, 1, 2, 3, 4, 6 }
s2U: { 0, 1, 2, 3, 4, 6 }
$