Lý do cơ bản cho sự không rõ ràng (tuân thủ tiêu chuẩn) dường như nằm trong chi phí chuyển đổi: Độ phân giải quá tải cố gắng giảm thiểu các hoạt động được thực hiện để chuyển đổi đối số thành thông số tương ứng. Một mảng là có hiệu quả là con trỏ đến phần tử đầu tiên của nó, được trang trí với một số thông tin kiểu thời gian biên dịch. Chuyển đổi mảng-thành-con trỏ không chi phí nhiều hơn ví dụ: lưu địa chỉ của chính mảng đó, hoặc khởi tạo một tham chiếu đến nó. Từ quan điểm đó, sự mơ hồ có vẻ hợp lý, mặc dù khái niệm nó không trực quan (và có thể là phân nhánh). Trong thực tế, đối số này áp dụng cho tất cả các biến đổi Lvalue, như được đề xuất bởi các báo giá dưới đây. Một ví dụ khác:
void g() {}
void f(void(*)()) {}
void f(void(&)()) {}
int main() {
f(g); // Ambiguous
}
Sau đây là bắt buộc standardese. Các hàm không phải là chuyên môn của một số mẫu chức năng được ưu tiên hơn so với các hàm nếu cả hai đều là một kết quả tương đương tốt (xem [over.match.best]/(1.3), (1.6)). Trong trường hợp của chúng tôi, chuyển đổi được thực hiện là chuyển đổi mảng-thành-con trỏ, là một phép chuyển đổi Lvalue với xếp hạng Đối sánh chính xác (theo bảng 12 trong [over.ics.user]). [Over.ics.rank]/3:
Điểm bullet đầu tiên không bao gồm chuyển đổi của chúng tôi (vì nó là một Chuyển đổi Lvalue).Điều thứ hai yêu cầu sự khác biệt về xếp hạng, không có mặt vì cả hai chuyển đổi đều có xếp hạng đối sánh chính xác; "Quy tắc trong đoạn bên dưới", tức là trong [over.ics.rank]/4, cũng không bao gồm chuyển đổi mảng-điểm trỏ.
Vì vậy, hãy tin hay không, không có trình tự chuyển đổi nào tốt hơn cả chuỗi kia và do đó, tải lên char const*
-overload.
Cách giải quyết khác: Xác định quá tải thứ hai làm mẫu chức năng, sau đó đặt một phần đá vào và chọn lần đầu tiên.
template <typename T>
auto foo(T s)
-> std::enable_if_t<std::is_convertible<T, char const*>{}>
{
std::cout << "raw, size=" << std::strlen(s) << std::endl;
}
Demo.
Liên quan: http://stackoverflow.com/questions/5347444/overload-resolution-and-arrays-which-function-should-be-called – 0x499602D2
'foo <> (" hello ");' sẽ gọi mẫu , nếu nó giúp. Tôi nghĩ đó là cách đơn giản để từ chối không phải mẫu. Và để buộc không sử dụng mẫu '(& foo) (" hello ")' - bạn có thể lấy địa chỉ của một mẫu không phải là mẫu, nhưng không phải là mẫu. –