Cuộc gọi đầu tiên chọn chuyên môn mẫu chức năng - bởi vì nó phù hợp hơn.
Chúng ta hãy đặt tên cả hai quá tải:
template<size_t N> void cm(const char (&h)[N]) // (1) - the specialization
{std::cout << " const (&)[N] " << endl;}
void cm(const char * h) // (2)
{cout << " const char * " << endl;}
Đối với (1), car
liên kết với một tài liệu tham khảo. Đó là chuyển đổi nhận dạng . Đối với (2), sau khi chuyển đổi mảng-thành-con trỏ của car
, trong đó mang lại char*
, một chuyển đổi tiêu chuẩn phải được thực hiện để char*
trở thành
char const*
. Mà bây giờ được gọi này:
tiêu chuẩn chuyển đổi chuỗi S1
là một chuỗi chuyển đổi tốt hơn so với chuỗi tiêu chuẩn chuyển đổi S2
nếu
S1
là một dãy con đúng S2
(so sánh trình tự chuyển đổi theo hình thức kinh điển được xác định bởi 13.3.3.1.1, không bao gồm bất kỳ Chuyển đổi Lvalue nào; trình tự chuyển đổi danh tính được coi là một dãy con của bất kỳ chuyển đổi phi sắc chuỗi) hoặc, nếu không muốn nói rằng,
- [...]
Một mảng-to-con trỏ Chuyển đổi là Chuyển đổi Lvalue, vì vậy nó không được xem xét ở đây - giống như trong ví dụ thứ hai. Chuyển đổi bằng cấp có danh mục riêng mặc dù: Điều chỉnh tiêu chuẩn. Do đó việc chuyển đổi thành tham số của (1) là một chuỗi chuyển đổi thành tham số của (2): đầu tiên là chuyển đổi nhận dạng và chuyển đổi thứ hai, và theo đoạn trên, chuyển đổi nhận dạng là một chuỗi bất kỳ chuyển đổi không nhận dạng nào. Vì vậy, (1) được chọn.
Như bạn đã tự đề cập, trong trường hợp thứ hai, các chuyển đổi đều tốt như nhau; Trích dẫn ở trên không hoạt động vì chuyển đổi sang tham số (2) s không phải là một chuỗi chuyển đổi cho tham số của (1). Do đó, [over.match.best]/1 được áp dụng.
Với những định nghĩa, một chức năng hữu hiệu đối F1
được định nghĩa là một hàm tốt hơn so với một chức năng hữu hiệu đối F2
nếu cho tất cả các đối i, ICSI (F1) không phải là một chuỗi chuyển đổi tồi tệ hơn ICSI (F2), và sau đó
- đối với một số tranh cãi j, ICSj (F1) là một chuỗi chuyển đổi tốt hơn ICSj (F2), hoặc, nếu không muốn nói rằng,
- bối cảnh là một khởi bởi chuyển đổi người dùng định nghĩa [...] hoặc, nếu không,
F1
là một hàm phi mẫu và F2
là một hàm mẫu chuyên môn,
Vì vậy, (2) một được chọn. Nếu mẫu chức năng không phải là mẫu nhưng hàm có thông số
char const (&)[8]
cuộc gọi sẽ không rõ ràng as Clang correctly says.
[over.ics.ref]/1:
Khi một tham số của kiểu tham chiếu liên kết trực tiếp (8.5.3) để một biểu thức luận , trình tự chuyển đổi ngầm là định danh chuyển đổi, trừ khi biểu thức đối số có loại là lớp bắt nguồn của loại tham số, trong trường hợp này, trình tự chuyển đổi tiềm ẩn là chuyển đổi từ cơ sở sang nguồn gốc (13.3.3.1).
[dcl.init.ref]/5 (mà là ở 8.5.3):
Trong tất cả các trường hợp ngoại trừ người cuối cùng (ví dụ, tạo và khởi tạo một tạm thời từ biểu thức khởi tạo) , tham chiếu được gọi là liên kết trực tiếp với biểu thức khởi tạo.
[conv.array]:
Một vế trái hoặc rvalue kiểu “mảng của N T
” hoặc “mảng không rõ ràng buộc của T
” có thể được chuyển đổi sang một prvalue loại "con trỏ đến T
". Kết quả là một con trỏ đến phần tử đầu tiên của mảng.
T
có thể đủ điều kiện cv và do đó loại điểm được chọn. Tại đây, T
chỉ là char
, vì vậy con trỏ có dạng con trỏ là char
=>char*
.
Huh, tôi không bao giờ biết rằng 'const char []' sẽ làm điều đó với một chuỗi chữ, tôi nghĩ nó sẽ hoạt động giống như 'char []' trong trường hợp này. –
Luận điểm trong đoạn cuối của câu trả lời là không đúng, phải không? – Columbo