Nhận xét đầu tiên (được bình chọn tốt) của câu trả lời được chấp nhận phàn nàn về một toán tử bị thiếu cho các hoạt động tập hợp std hiện có.
Một mặt, tôi hiểu việc thiếu các toán tử như vậy trong thư viện chuẩn. Mặt khác, có thể dễ dàng thêm chúng (vì niềm vui cá nhân) nếu muốn. Tôi quá tải
operator *()
cho sự giao nhau của các bộ
operator +()
cho liên hiệp các bộ.
Mẫu 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;
}
Tổng hợp và thử nghiệm:
$ 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 }
$
Điều tôi không thích là bản sao của các giá trị trả về trong các toán tử. Có thể là, điều này có thể được giải quyết bằng cách sử dụng nhiệm vụ di chuyển nhưng điều này vẫn nằm ngoài khả năng của tôi.
Do kiến thức hạn chế của tôi về các ngữ nghĩa chuyển động "mới lạ" này, tôi lo ngại về việc trả về toán tử có thể gây ra các bản sao của các tập hợp được trả về. Olaf Dietsche chỉ ra rằng những mối quan tâm này là không cần thiết vì std::set
đã được trang bị hàm tạo / gán di chuyển.
Mặc dù tôi tin anh ấy, nhưng tôi đang nghĩ cách kiểm tra điều này (ví dụ như "tự thuyết phục"). Trên thực tế, nó là khá dễ dàng. Vì các mẫu phải được cung cấp trong mã nguồn, bạn có thể chỉ cần thực hiện qua trình gỡ lỗi. Vì vậy, tôi đặt một điểm break ngay tại return s;
của operator *()
và tiến hành với single bước mà pha chì cho tôi ngay lập tức vào std::set::set(_myt&& _Right)
: et thì đấy - các nhà xây dựng di chuyển. Cảm ơn, Olaf, vì sự chú ý (của tôi).
Để hoàn thiện, tôi cũng đã triển khai các toán tử gán tương ứng
operator *=()
cho giao điểm "phá hủy" của các tập hợp
operator +=()
cho liên hiệp các tập hợp "phá hoại".
Mẫu 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;
}
Tổng hợp và thử nghiệm:
$ 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 }
$