2013-03-20 32 views
11

Phạm vi mới dựa trên các vòng thực sự cải thiện khả năng đọc và thực sự dễ sử dụng. Tuy nhiên, hãy xem xét những điều sau đây:C++ 11 dựa trên phạm vi và bản đồ: khả năng đọc

map<Foo,Bar> FooAndAssociatedBars; 

for (auto& FooAndAssociatedBar : FooAndAssociatedBars) { 
    FooAndAssociatedBar.first.doSth(); 
    FooAndAssociatedBar.second.doSomeOtherThing(); 
} 

Nó có thể là một chi tiết nhưng tôi thấy nó đã có thể đọc được nhiều hơn nếu tôi có thể làm điều gì đó như:

for ((auto& foo, auto& bar) : FooAndAssociatedBars) { 
    foo.doSth(); 
    bar.doSomeOtherThing(); 
} 

Bạn có biết một cú pháp tương đương?

EDIT: Tin tốt: C++ 17 có một đề nghị rằng adresses vấn đề này, được gọi là các ràng buộc có cấu trúc (xem 1). Trong C++ 17, bạn sẽ có thể viết:

tuple<T1,T2,T3> f(/*...*/) { 
    /*...*/ 
    return {a,b,c}; 
} 
auto [x,y,z] = f(); // x has type T1, y has type T2, z has type T3 

mà giải quyết vấn đề dễ đọc này

+0

Trình biên dịch đoán câu 'Foo' và' Bar' có nghĩa là gì? –

+0

@PeteBecker Vâng, foo chỉ là một cách thuận tiện để nói "tên foo phần bên trái của std :: cặp". Nói một cách tuyệt đối, có thể thực hiện điều này vào thời gian biên dịch: đây chỉ là một sự thuận tiện không hợp lý. Tôi đã tự hỏi nếu nó có thể có được hiệu ứng như vậy thông qua quá tải hoặc một cái gì đó như thế –

+0

Có, nó chắc chắn có thể yêu cầu trình biên dịch để biết về 'std :: pair' hoặc để tìm bất kỳ struct với các yếu tố có tên' first' và ' thứ hai'; đó là khá chuyên môn, và có lẽ không thích hợp cho việc tiêu chuẩn hóa. Yêu cầu tiếp theo sẽ là cho tất cả các phần tử của 'tuple' ... –

Trả lời

10

Không có những điều như bạn muốn. Cách gần nhất là khai báo các biến trong vòng lặp:

for (auto& FooAndAssociatedBar : FooAndAssociatedBars) { 
    auto& foo = FooAndAssociatedBar.first; 
    auto& bar = FooAndAssociatedBar.second; 

    // ... 
} 
0

Và tất nhiên, bạn luôn có khả năng sử dụng lambdas.

std::map<int, const char*> m { { 4, "hello" }, { 11, "c++" } }; 
convenient_for_each(m, [](int a, const char* b) { 
    std::cout << b << a << std::endl; 
    }); 
convenient_for_each(m, [](std::pair<int, const char> p) { 
    std::cout << p.first << p.second << std::endl; 
    }); 

Hoặc bọc như vĩ mô (không khuyến khích)

FOREACH((int a, const char* b), m, std::cout << a << b << std::endl); 
FOREACH((std::pair<int, const char*> p), m, std::cout << p.first << p.second << std::endl); 

(Hackish sample implementation at LWS)

Auto sẽ không làm việc, mặc dù tôi vẫn đang chờ đợi lambdas đa hình. Cách tiếp cận của tôi về mặt lý thuyết cũng có thể xử lý các bộ dữ liệu.

1

Không phải là ý hay. Sớm hay muộn, bạn sẽ muốn như vậy cho một std::tuple, và trình biên dịch sẽ có thể sử dụng std::get<> trên tuple tự động. Theo tôi, cách tiếp cận của bạn là làm hài lòng bạn vào lúc này, và bạn sẽ tìm thấy vấn đề với cách tiếp cận này (giả sử nó được thực hiện theo cách đó).

Ủy ban tiêu chuẩn đã thiết kế phạm vi dựa trên vòng lặp có cân nhắc sâu. Nó là cách tốt hơn so với foreach vòng lặp trong các ngôn ngữ khác, và nó là cách ngắn hơn. Hãy ghép đôi với auto& và bạn đã hoàn tất!

+1

" Không phải là một ý tưởng tốt. Sớm hay muộn, bạn sẽ muốn như vậy cho một std :: tuple, và trình biên dịch sẽ có thể sử dụng std :: get <> trên tuple tự động. " Và vấn đề với điều đó là gì? – Cubic

+0

Nhu cầu khác từ trình biên dịch. – Ajay

+0

Làm thế nào? Cách tôi nhìn thấy nó bất kỳ tính năng ngôn ngữ như vậy sẽ được định nghĩa để gọi 'std :: get' (cũng không đủ tiêu chuẩn' get' nhiều khả năng) và do đó hỗ trợ 'std :: pair' và' std :: tuple' và bất kỳ người dùng được định nghĩa ' tuple' giống như các thùng chứa tự động. – Grizzly

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