ความคิดเห็นแรก (ได้รับการโหวตอย่างดี) ของคำตอบที่ยอมรับบ่นเกี่ยวกับตัวดำเนินการที่ขาดหายไปสำหรับการดำเนินการชุดมาตรฐานที่มีอยู่
ในแง่หนึ่งฉันเข้าใจว่าไม่มีตัวดำเนินการดังกล่าวในไลบรารีมาตรฐาน ในทางกลับกันมันเป็นเรื่องง่ายที่จะเพิ่ม (เพื่อความสุขส่วนตัว) หากต้องการ ฉันทำงานหนักเกินไป
operator *()
สำหรับการตัดกันของชุด
operator +()
สำหรับการรวมกันของชุด
ตัวอย่างtest-set-ops.cc
:
#include <algorithm>
#include <iterator>
#include <set>
template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC> operator * (
const std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
std::set<T, CMP, ALLOC> s;
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
std::inserter(s, s.begin()));
return s;
}
template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC> operator + (
const std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
std::set<T, CMP, ALLOC> s;
std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(),
std::inserter(s, s.begin()));
return s;
}
#include <iostream>
using namespace std;
template <class T>
ostream& operator << (ostream &out, const set<T> &values)
{
const char *sep = " ";
for (const T &value : values) {
out << sep << value; sep = ", ";
}
return out;
}
int main()
{
set<int> s1 { 1, 2, 3, 4 };
cout << "s1: {" << s1 << " }" << endl;
set<int> s2 { 0, 1, 3, 6 };
cout << "s2: {" << s2 << " }" << endl;
cout << "I: {" << s1 * s2 << " }" << endl;
cout << "U: {" << s1 + s2 << " }" << endl;
return 0;
}
รวบรวมและทดสอบ:
$ 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 }
$
สิ่งที่ฉันไม่ชอบคือสำเนาของค่าส่งคืนในตัวดำเนินการ อาจเป็นไปได้ว่าสิ่งนี้สามารถแก้ไขได้โดยใช้การมอบหมายการย้าย แต่ก็ยังเกินทักษะของฉัน
เนื่องจากความรู้ที่ จำกัด ของฉันเกี่ยวกับความหมายของการย้าย "แฟนซีใหม่" เหล่านี้ฉันจึงกังวลเกี่ยวกับการส่งคืนตัวดำเนินการซึ่งอาจทำให้เกิดสำเนาของชุดที่ส่งคืน Olaf Dietscheชี้ให้เห็นว่าข้อกังวลเหล่านี้ไม่จำเป็นเนื่องจากstd::set
มีตัวสร้าง / มอบหมายการเคลื่อนย้ายอยู่แล้ว
แม้ว่าฉันจะเชื่อเขา แต่ฉันก็คิดว่าจะตรวจสอบสิ่งนี้อย่างไร (สำหรับบางอย่างเช่น "การเชื่อมั่นในตนเอง") จริงๆแล้วมันค่อนข้างง่าย เนื่องจากต้องมีเทมเพลตในซอร์สโค้ดคุณสามารถทำตามขั้นตอนด้วยโปรแกรมดีบั๊ก ดังนั้นฉันจึงวางจุดพักไว้ที่ด้านขวาreturn s;
ของoperator *()
และดำเนินการต่อด้วยขั้นตอนเดียวซึ่งนำฉันไปสู่std::set::set(_myt&& _Right)
: et voilà - ตัวสร้างการย้าย ขอบคุณโอลาฟสำหรับการรู้แจ้ง (ของฉัน)
เพื่อความสมบูรณ์ฉันใช้ตัวดำเนินการมอบหมายที่เกี่ยวข้องด้วย
operator *=()
สำหรับจุดตัดของชุด "ทำลายล้าง"
operator +=()
สำหรับการรวมกลุ่มของชุด "ทำลายล้าง"
ตัวอย่างtest-set-assign-ops.cc
:
#include <iterator>
#include <set>
template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC>& operator *= (
std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &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 T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC>& operator += (
std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
s1.insert(s2.begin(), s2.end());
return s1;
}
#include <iostream>
using namespace std;
template <class T>
ostream& operator << (ostream &out, const set<T> &values)
{
const char *sep = " ";
for (const T &value : values) {
out << sep << value; sep = ", ";
}
return out;
}
int main()
{
set<int> s1 { 1, 2, 3, 4 };
cout << "s1: {" << s1 << " }" << endl;
set<int> s2 { 0, 1, 3, 6 };
cout << "s2: {" << s2 << " }" << endl;
set<int> s1I = s1;
s1I *= s2;
cout << "s1I: {" << s1I << " }" << endl;
set<int> s2I = s2;
s2I *= s1;
cout << "s2I: {" << s2I << " }" << endl;
set<int> s1U = s1;
s1U += s2;
cout << "s1U: {" << s1U << " }" << endl;
set<int> s2U = s2;
s2U += s1;
cout << "s2U: {" << s2U << " }" << endl;
return 0;
}
รวบรวมและทดสอบ:
$ 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 }
$