Nếu các phần tử trong std::initializer_list
luôn là giá trị const, tại sao chúng ta có phương thức mẫu như begin()/end()
chứ không phải cbegin()/cend()
? Tên này (theo quy ước, so sánh với ví dụ: std::vector
) có thể gợi ý rằng cả hai phương pháp std::initializer_list
đều có thể trả về iterator
, khi chúng luôn trả về const_iterator
.std :: initializer_list không có cbegin()/cend()
Trả lời
Trong khi tôi không thể cung cấp một cái nhìn sâu sắc về lý do tại sao cbegin()
và cend()
không nằm trong giao diện ngoài std::initializer_list
's đểbegin()
và end()
, chắc chắn có lý do chính đáng tại sao hai hàm thành viên cuối cùng nên được đó.
Một lý do là, ví dụ, vòng lặp dựa trên phạm vi for
được xác định bởi tiêu chuẩn C++ 11 chính xác về các hàm begin()
và end()
(Đoạn 6.5.4/1). Vì vậy, để làm cho nó có thể sử dụng nó với danh sách khởi tạo, std::initializer_list
có để cung cấp các begin()
và end()
thành viên chức năng:
#include <utility>
#include <iostream>
int main()
{
auto l = { 1, 2, 3, 4, 5 };
for (int x : l) // Works because std::initializer_list provides
// the member functions begin() and end().
{
std::cout << x << " ";
}
}
Hơn nữa, nó làm cho tinh thần để xem xét rằng chức năng thành viên cbegin()
và cend()
không có mặt trước C++ 11: do đó, có begin()
và end()
trên giao diện std::initializer_list
cho phép thực hiện các thuật toán chung cũ được viết theo số begin()
và end()
hoạt động với danh sách trình khởi tạo, mà không yêu cầu chúng được viết lại.
Bạn viết:
Những tên (theo quy ước, so với ví dụ
std::vector
) có thể gợi ý rằng cả haistd::initializer_list
phương pháp có thể trở lạiiterator
, khi họ luôn luôn trảconst_iterator
.
Thực ra, sự tương tự này không phù hợp lắm. Ví dụ, hàm begin()
của std::vector
trả về số iterator
khi được gọi trên một số không const
của std::vector
(tức là một biến thể có thể thay đổi, thêm và xóa) và const_iterator
khi được gọi trên cá thể const
(tức là một cái không thể thay đổi được, có nội dung không thể thay đổi được):
#include <vector>
#include <type_traits>
int main()
{
// A non-const vector...
std::vector<int> v = { 1, 2, 3, 4, 5 };
auto i = v.begin();
static_assert(
std::is_same<decltype(i), decltype(v)::iterator>::value,
// ^^^^^^^^
// ...non-const iterator!
"What?");
// A const vector...
std::vector<int> const vc = { 1, 2, 3, 4, 5 };
auto ic = vc.begin();
static_assert(
std::is_same<decltype(ic), decltype(vc)::const_iterator>::value,
// ^^^^^^^^^^^^^^
// ...const iterator!
"What?");
}
Danh sách khởi tạo là những tập hợp bất biến theo định nghĩa. Theo Đoạn 18.9/2 của tiêu chuẩn C++ 11:
Đối tượng loại
initializer_list<E>
cung cấp quyền truy cập vào một mảng đối tượng thuộc loạiconst E
. [...]
Kể từ danh sách khởi tạo là bộ sưu tập của const
yếu tố, các cbegin()
và cend()
chức năng thực sự sẽ làm chính xác những điều tương tự mà begin()
và end()
làm.
Trong thực tế, iterator
và const_iterator
đều định nghĩa là con trỏ đến các yếu tố liên tục của kiểu giá trị trong danh sách khởi tạo, vì vậy nó là đáng tranh cãi cho dù đó là những trường hợp đó begin()
và end()
luôn luôn trả const_iterator
(như bạn giả định), hoặc cho dù họ luôn trả lại iterator
.
Đây là cách Đoạn 18,9/1 của C++ 11 Tiêu chuẩn xác định các mẫu initializer_list
lớp:
namespace std {
template<class E> class initializer_list {
public:
typedef E value_type;
// ...
typedef const E* iterator;
typedef const E* const_iterator;
// ...
constexpr const E* begin() const noexcept; // first element
constexpr const E* end() const noexcept; // one past the last element
};
// ...
}
Tôi nhớ khi tôi đã từng kiếm tiền trên SO, nhưng sau đó một số người đến và trả lời tất cả các câu hỏi C++ tốt ở dạng xuất sắc . Bây giờ tôi chỉ có thể bình chọn. +1 – GManNickG
@GManNickG: Tôi rất vui, và mặc dù tôi tin rằng bạn đang khen tôi nhiều hơn tôi xứng đáng, tôi rất vui khi nhận được sự hỗ trợ của bạn. Cảm ơn bạn. –
@GManNickG: Chỉ cần nghĩ về tất cả những người C# đã từng là JonSkeeted kể từ ngày 1. – MSalters
- 1. Cấu trúc cơ bản của std :: initializer_list là gì?
- 2. std :: unique_ptr xóa chức năng, initializer_list - điều khiển phân bổ
- 3. Chuyển đổi variadic mẫu gói vào std :: initializer_list
- 4. Tại sao hành vi initializer_list của C++ cho std :: vector và std :: array khác nhau?
- 5. Cách sử dụng initializer_list
- 6. initializer_list và kiểu mẫu trích
- 7. vector tuple và initializer_list
- 8. Tại sao kích thước không phải là đối số mẫu của std :: initializer_list?
- 9. suy luận kiểu với rvalue initializer_list
- 10. Xác thực nội dung của std :: initializer_list tại thời gian biên dịch
- 11. Toán tử bậc ba + hàm tạo C++ 11 từ initializer_list
- 12. Không thể sao chép std :: vector <std :: function <void()>> sử dụng khởi tạo đồng bộ. Điều này có đúng không?
- 13. std :: hash_set vs std :: unordered_set, chúng có giống nhau không?
- 14. Bất cứ ai cũng cho tôi một ví dụ để sử dụng QVector :: QVector (std :: initializer_list <T> args)?
- 15. C# có tương đương std :: nth_element không?
- 16. tôi có cần đóng std :: fstream không?
- 17. Tại sao không có std :: stou?
- 18. Tại sao không std :: pair có iterators?
- 19. Có std :: cout có giá trị trả lại không?
- 20. Có phải "std :: size_t" có ý nghĩa trong C++ không?
- 21. std không chặn :: getline, thoát nếu không có đầu vào
- 22. không gian tên "std" không có thành viên "sắp xếp"
- 23. Khi khởi tạo std :: array
- 24. C++, tôi có thể khởi tạo tĩnh std :: map tại thời gian biên dịch không?
- 25. Bạn có sử dụng std :: shared_ptr <std::vector> thay vì tăng :: shared_array không?
- 26. Bạn có thể sử dụng `std :: remove_if` trên vùng chứa` std :: unique_ptr` không?
- 27. Liệu std :: nguyên tử <std::string> có hoạt động phù hợp không?
- 28. Có điều gì giống như "std :: và" hoặc "std :: hay" không?
- 29. Có phải std :: ofstream movable?
- 30. Có std :: stack expose iterators?
Một câu hỏi hay. Làm tốt. –
@LightnessRacesinOrbit Xin chào, rất vui được gặp bạn tại đây :-) – Des1gnWizard
@ Des1gnWizard: Đây không phải là trang web hẹn hò, cảm ơn. –