2014-12-15 42 views
9

Tôi muốn để có thể viết bằng C++ một cái gì đó tương tự như đoạn mã sau Python:Kiểm tra xem một yếu tố là trong std :: initializer_list

if x in [1, 2, 3, 5] ... 

để kiểm tra xem một phần tử được chứa trong một tập hợp các hard- các giá trị được mã hóa, được xác định tại chỗ. Như thế này:

if (in(x, {1, 2, 3, 5})) ... 

Đây là việc thực hiện tốt các chức năng in:

template<class T> 
bool in(const T& x, std::initializer_list<T> c) 
{ 
    return std::find(c.begin(), c.end(), x) != c.end(); 
} 

Câu hỏi của tôi là: Tôi thực sự phải viết chức năng này bằng cách bản thân mình? Có bất kỳ triển khai mặc định nào ở đó không? Có lẽ trong tăng? Tôi đã kiểm tra boost::contains, nhưng nó chỉ hoạt động với các chuỗi.

+1

Không có gì tốt hơn trong C++. Nhưng, bạn có thực sự cần (thuận tiện) ngữ nghĩa python trong c + +? –

+2

Theo nguyên tắc chung, Python là "bao gồm pin" .... C++ là "làm cho pin của riêng bạn từ đầu". –

+1

Bằng cách này, tại sao không bỏ qua các niềng răng và sử dụng một mẫu variadic? Hoặc là ít có thể đọc được? – Columbo

Trả lời

2

Từ một std::set 's count chỉ trả về 1 hoặc 0 bạn chỉ có thể sử dụng: (. Và gây ra 5 mùa của Lost)

if(set<int>{4, 8, 15, 16, 23, 42}.count(x)) 

Hãy ghi nhớ rằng số trần thể gây nhầm lẫn cho khán giả của bạn
Tôi khuyên bạn nên khai báo số của mình là const và đặt cho chúng một tên có ý nghĩa.

const std::initializer_list<int> finalCandidates{4, 8, 15, 16, 23, 42}; 

if(finalCandidates.end() != std::find(finalCandidates.begin(), finalCandidates.end(), x)) 
+0

Bạn nên khai báo 'foo' với' auto'. – Mikhail

+0

@Mikhail có lý do 'auto' sẽ thích hợp hơn không? –

+0

Có. Cuốn sách tôi đã đề cập trong câu hỏi dành toàn bộ chương giải thích tại sao. – Mikhail

5

boost::algorithm::contains không chỉ hoạt động trên chuỗi, nó hoạt động trên bất kỳ phạm vi , tức là chuỗi có thể mang lại trình lặp đầu và cuối. Để tìm một giá trị duy nhất sử dụng nó như sau:

auto l = {1,2,3,4}; 
auto l1 = {2};  // thing you want to find 
if(boost::algorithm::contains(l, l1)) { ... } 

Bạn có thể thực hiện tìm kiếm của bạn bằng cách sử dụng thư viện tiêu chuẩn duy nhất, nhưng làm như vậy là khá một chút dài dòng hơn. Một vài tùy chọn là:

  1. sử dụng một lambda

    if(std::any_of(l.begin(), l.end(), 
           [](int i){ return i == 2; })) { ... } 
    
  2. sử dụng std::bind

    using std::placeholders::_1; 
    if(std::any_of(l.begin(), l.end(), 
           std::bind(std::equal_to<>(), 2, _1)) { ... } 
    

Live demo

Lưu ý rằng std::equal_to<>() là tùy chọn chỉ có C++ 14. Đối với trình biên dịch C++ 11, sử dụng std::equal_to<int>().

+0

Ồ, bạn nói đúng. Tôi đã cố gắng để xác định các phạm vi tại chỗ, và loại khấu trừ không thành công, vì nó không thể suy ra loại 'initializer_list'. Đó là lý do tại sao nó không thể được sử dụng cho nhiệm vụ của tôi trực tiếp. Thật đáng buồn. – Mikhail

+1

@Mikhail Vâng, rất tiếc là trích dẫn đối số mẫu sẽ không suy ra 'initializer_list' từ danh sách-init-braced. Viết một hàm giống như hàm bạn có là cách để đi nếu bạn không muốn tạo tạm thời 'initializer_list'. Hoặc bạn có thể chỉ định kiểu rõ ràng: 'if (boost :: algorithm :: contains (std :: initializer_list {1,2,3,4}, std :: initializer_list {2}))' – Praetorian

+0

đặt trong trường hợp noexcept specifier cho lambda – user1095108

1

Thực tế STL không có hàm std::contains() đơn giản. Gần đây, đã có một số discussion on reddit về chủ đề này.

Thật không may, những gì xuất phát từ điều này là nó được coi là có hại khi có std::contains(), vì nó khuyến khích mọi người viết các thuật toán chậm. Hãy suy nghĩ ví dụ:

if (!std::contains(my_set.begin(), my_set.end(), entry)) { 
    my_set.insert(insert); 
} 

Ví dụ mã này về cơ bản tìm kiếm vị trí chính xác hai lần: Một lần chứa và một lần để tìm vị trí chèn.

Theo ý kiến ​​của tôi, sẽ rất hữu ích khi có std::contains(), nhưng cho đến nay chưa có ai được thuyết phục để viết đề xuất.

Vì vậy, hoặc thúc đẩy sử dụng (theo đề nghị của khác trong chủ đề này), hoặc viết chức năng của riêng bạn mà bạn về cơ bản đã làm :-)

+0

Tôi không đồng ý với kết luận này, nhưng cảm ơn bạn đã chia sẻ! – Mikhail

Các vấn đề liên quan