2014-12-20 25 views
8

Trong cố gắng để biên dịch đoạn mã sau đó sẽ sao chép một map s phím để một vector:Tại sao tôi không thể sử dụng std :: nhận được <0> trong std :: transform?

map<string, string> mss; 
vector<string> vs; 

transform(mss.begin(), mss.end(), back_inserter(vs), get<0>); 

VS2013 không thể phân biệt mà get được thiết kế nhưng sử dụng đơn giản này chỉ hoạt động tốt:

vs.push_back(get<0>(*mss.begin())); 

Chỉ định get<0, string, string> không giúp ích gì. Tôi đang thiếu gì?

Trả lời

8

Có nhiều quá tải std::get, trong đó, ngoài ra, mỗi mẫu là một mẫu hàm, do đó trình biên dịch không thể cho biết bạn muốn trang web nào yêu cầu địa chỉ của một trong số chúng. Nếu bạn nhấn mạnh vào việc sử dụng std::get, bạn sẽ cần phải sử dụng static_cast:

transform(mss.begin(), mss.end(), back_inserter(vs), 
      static_cast<const map<string, string>::key_type& 
         (*)(map<string, string>::value_type&)>(std::get<0>) 
        ); 

nào sẽ làm việc miễn là gõ vào static_cast phù hợp với tuyên bố của chuyên môn hóa một chức năng có thể sửa mẫu cho làm đối số. Ngoài ra, bạn không nên cố gắng xác định rõ ràng các đối số mẫu của các mẫu chức năng như get<0, string, string> v.v. - đây là cơ chế khấu trừ đối số khuôn mẫu cho cái gì. Cú pháp không chỉ xấu xí, mà còn có thể có các tình trạng quá tải khác được thêm vào trong tương lai phá vỡ quá trình biên dịch của bạn.

Một lựa chọn tốt hơn nhiều là sử dụng một biểu thức lambda :

transform(mss.begin(), mss.end(), back_inserter(vs), 
      [](map<string, string>::value_type& p){ return p.first; }); 

hoặc một generic biểu thức lambda (C++ 14):

transform(mss.begin(), mss.end(), back_inserter(vs), 
      [](auto& p){ return p.first; }); // or `return std::get<0>(p);` 

hoặc std::mem_fn mà liên kết với nó đối số cho một con trỏ cho một thành viên dữ liệu hoặc một hàm thành viên:

#include <functional> 

transform(mss.begin(), mss.end(), back_inserter(vs), 
      mem_fn(&map<string, string>::value_type::first)); 
+1

Cảm ơn. Tôi đã hy vọng có thể giữ được siêu ngắn gọn 'get <0>' nhưng ... nó không có nghĩa là. Ồ, tốt. – screwnut

5

Thành viên đầu tiên của cặp được lưu trữ trong bản đồ là đủ điều kiện. Vì vậy, về mặt kỹ thuật bạn cần

get<0, const string, string> 

Nhưng điều đó không hạn chế danh sách các ứng cử viên cho một tình trạng quá tải rõ ràng, kể từ get có sẵn trong ít nhất hai phiên bản: đối với lập luận tham chiếu const và cho lập luận tài liệu tham khảo không const.

Bạn có thể chọn một bằng cách sử dụng một dàn diễn viên

const string &(*g)(const pair<const string, string> &) = 
    get<0, const string, string>; 

hoặc

typedef map<string, string> Map; 

const Map::key_type &(*g)(const Map::value_type &) = 
    get<0, const Map::key_type, Map::mapped_type>; 

và sau đó làm

transform(mss.begin(), mss.end(), back_inserter(vs), g); 
Các vấn đề liên quan