2012-03-09 49 views
68

Tôi chỉ đang phát xung quanh với g ++ 4.7 (một trong những ảnh chụp nhanh sau) đã bật -std = C++ 11. Tôi đã cố gắng biên dịch một số cơ sở mã hiện có của mình và một trường hợp không thành công gây nhầm lẫn cho tôi.C++ 11 make_pair với các tham số mẫu được chỉ định không biên dịch

Tôi sẽ đánh giá cao nếu ai đó có thể giải thích những gì đang diễn ra.

Dưới đây là đoạn code

#include <utility> 
#include <iostream> 
#include <vector> 
#include <string> 

int main () 
{ 
    std::string s = "abc"; 

    // 1 ok 
    std::pair < std::string, int > a = std::make_pair (s, 7); 

    // 2 error on the next line 
    std::pair < std::string, int > b = std::make_pair < std::string, int > (s, 7); 

    // 3 ok 
    std::pair < std::string, int > d = std::pair < std::string, int > (s, 7); 

    return 0; 
} 

Tôi hiểu make_pair đó là nghĩa được sử dụng như là (1) trường hợp (nếu tôi chỉ định các loại, sau đó tôi cũng có thể sử dụng (3)), Nhưng Tôi không hiểu tại sao nó lại thất bại trong trường hợp này.

Các lỗi chính xác là:

test.cpp: In function ‘int main()’: test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’ test.cpp:11:83: note: candidate is: In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0, from test.cpp:1: /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template constexpr std::pair::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template argument deduction/substitution failed: test.cpp:11:83: note: cannot convert ‘s’ (type ‘std::string {aka std::basic_string}’) to type ‘std::basic_string&&’

Một lần nữa, câu hỏi ở đây chỉ là "những gì đang xảy ra?" Tôi biết rằng tôi có thể khắc phục vấn đề bằng cách loại bỏ đặc tả mẫu, nhưng tôi chỉ muốn biết những gì đang thất bại ở đây dưới trang bìa. Cảm ơn trước.

EDIT:

  • g ++ 4.4 biên dịch mã này không có vấn đề.
  • Xóa -std = C++ 11 cũng biên dịch bằng mã không có sự cố.
+5

Một câu hỏi tuyệt vời. Tuy nhiên, một ví dụ khác về sự thay đổi phá vỡ tinh tế trong C++ 11, tương tự như [thay đổi đột phá trong 'std :: vector' construction] (http://stackoverflow.com/questions/5759232/stdvector-default-construction-c11- và đột phá). Ít nhất điều này mang lại một lỗi trình biên dịch và không phải là một sự thay đổi thầm lặng trong ngữ nghĩa. –

+1

Nếu tôi có biến số nguyên i. Tôi muốn ghép đôi với tôi và một vật thể khác. Làm thế nào chính xác tôi nên gọi là tuyệt vọng. 1) make_pair <*i, obj> 2) int && j = i; make_pair ? Cả hai đều không hoạt động. Whats cách chính xác để làm điều đó? – PHcoDer

Trả lời

108

Đây không phải là cách std::make_pair được thiết kế để sử dụng; bạn không được chỉ định rõ ràng các đối số mẫu.

C++ 11 std::make_pair lấy hai đối số, thuộc loại T&&U&&, trong đó TU là thông số loại mẫu. Một cách hiệu quả, nó trông như thế này (bỏ qua các kiểu trả về):

template <typename T, typename U> 
[return type] make_pair(T&& argT, U&& argU); 

Khi bạn gọi std::make_pair và xác định rõ ràng các đối số mẫu kiểu, không có khấu trừ lập luận diễn ra. Thay vào đó, các đối số kiểu được thay thế trực tiếp vào khai báo mẫu, yielding:

[return type] make_pair(std::string&& argT, int&& argU); 

Lưu ý rằng cả hai loại tham số này là tham chiếu rvalue. Vì vậy, họ chỉ có thể liên kết với các giá trị. Đây không phải là vấn đề đối với đối số thứ hai mà bạn vượt qua, 7, bởi vì đó là biểu thức giá trị. Tuy nhiên, s là một biểu thức giá trị (nó không phải là tạm thời và nó không được di chuyển). Điều này có nghĩa là mẫu chức năng không phù hợp với các đối số của bạn, đó là lý do tại sao bạn nhận được lỗi.

Vì vậy, tại sao nó hoạt động khi bạn không xác định rõ ràng những gì TU nằm trong danh sách đối số mẫu? Trong ngắn hạn, tham số rvalue tham số là đặc biệt trong các mẫu. Một phần do tính năng ngôn ngữ được gọi là tham chiếu thu gọn, thông số tham chiếu rvalue của loại A&&, trong đó A là thông số loại mẫu, có thể liên kết với bất kỳ loại A nào.

Nó không quan trọng cho dù A là một giá trị trái, một rvalue, const-đủ điều kiện, biến động có trình độ, hoặc không đủ tiêu chuẩn, một A&& thể liên kết với đối tượng đó (một lần nữa, khi và chỉ khi A là chính nó một tham số mẫu).

Trong ví dụ của bạn, chúng tôi thực hiện cuộc gọi:

make_pair(s, 7) 

Ở đây, s là một vế trái của loại std::string7 là một rvalue loại int. Vì bạn không chỉ định các đối số mẫu cho mẫu hàm, việc trích lập đối số mẫu được thực hiện để tìm ra các đối số là gì.

Để ràng buộc s, một giá trị trái, để T&&, trình biên dịch deduces Tstd::string&, năng suất một đối số kiểu std::string& &&. Tuy nhiên, không có tham chiếu đến tham chiếu, do đó, "tham chiếu kép" này sụp đổ để trở thành std::string&. s là kết quả phù hợp.

Nó đơn giản để ràng buộc 7 để U&&: trình biên dịch có thể suy ra Uint, năng suất một tham số kiểu int&&, mà liên kết thành công để 7 bởi vì nó là một rvalue.

Có rất nhiều sự tinh tế với các tính năng ngôn ngữ mới, nhưng nếu bạn làm theo một quy tắc đơn giản, nó là khá dễ dàng:

If a template argument can be deduced from the function arguments, let it be deduced. Don't explicitly provide the argument unless you absolutely must.

Let the compiler do the hard work, and 99.9% of the time it'll be exactly what you wanted anyway. When it isn't what you wanted, you'll usually get a compilation error which is easy to identify and fix.

+6

Đây là một lời giải thích rất tốt và toàn diện. Cảm ơn bạn! – vmpstr

+1

@James - là "một quy tắc đơn giản" từ một bài viết hoặc câu trả lời khác tôi nên đọc? –

+4

@MichaelBurr: Không, tôi vừa mới làm điều đó. :-) Vì vậy, tôi hy vọng nó là sự thật! Tôi nghĩ đó là sự thật ... quy tắc đó luôn hoạt động cho tôi khá nhiều. –

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