2012-02-25 40 views
11

Tôi đang bối rối bởi tình huống này và googling đã không cho tôi câu trả lời. Về cơ bản tôi có mã đơn giản sau đây mà không biên dịch:Gọi mơ hồ đến chức năng tĩnh quá tải

#include <iostream> 

class A 
{ 
public: 
    int a(int c = 0) { return 1; } 
    static int a() { return 2; } 
}; 

int main() 
{ 
    std::cout << A::a() << std::endl; 
    return 0; 
} 

Trong biên soạn này, GCC 4.2 cho biết cuộc gọi đến A::a() trong main() không rõ ràng với cả hai phiên bản a() ứng cử viên hợp lệ. Trình biên dịch LLVM của Apple 3.0 biên dịch không có lỗi.

Tại sao gcc nhầm lẫn về chức năng tôi muốn gọi? Tôi nghĩ rõ ràng là bằng cách đủ điều kiện a() với A:: Tôi yêu cầu phiên bản static của hàm. Đương nhiên mã này vẫn không biên dịch nếu tôi xóa chức năng statica(), vì A::a() không phải là cú pháp hợp lệ để gọi số .

Cảm ơn mọi nhận xét!

+0

BTW, tìm kiếm nhanh trên google của tôi: "Độ phân giải tên của các hàm thành viên tĩnh và không tĩnh C++" đã đưa ra một câu hỏi SO khác: http: //stackoverflow.com/questions/5365689/c-overload-static-function -with-non-static-function – Bingo

+0

oops google-fu của tôi không thành công ... – fang

Trả lời

6

Lý do cho điều này là vì C++ xác định rằng điều này không rõ ràng. Độ phân giải quá tải chỉ định rằng đối với A::a, vì this không nằm trong phạm vi, danh sách đối số trong cuộc gọi đó được tăng thêm bởi contrived Đối số đối tượng, thay vì *this. Độ phân giải quá tải không loại trừ các chức năng thành viên không tĩnh, nhưng thay vào đó là

Nếu danh sách đối số được tăng cường bởi đối tượng contrived và độ phân giải quá tải chọn một trong các chức năng thành viên không tĩnh của T, cuộc gọi bị hỏng .

Điều này gần đây đã được thảo luận rộng rãi cả trong ủy ban theo ngữ cảnh core issue 1005. Xem core issue 364 xem xét việc thay đổi quy tắc này nhưng không làm như vậy.

+0

Cảm ơn bạn đã tham khảo. Tuy nhiên tôi vẫn đang đấu tranh để hiểu, tại sao "quá tải độ phân giải chọn một trong các chức năng thành viên không tĩnh của T". Nếu tôi hiểu những gì bạn nói đúng, a() không tĩnh có hai đối số: điều này và đối số với giá trị mặc định (c = 0). Các a() tĩnh có một đối số "contrived A". Bởi vì tôi không cung cấp một con trỏ "này" trong cuộc gọi, tại sao phiên bản không tĩnh sẽ được chọn? – fang

+0

Không, 'this' không phải là một đối số trong cuộc gọi này vì không có' this' trong phạm vi. Đó là lý do chúng tôi vượt qua "một đối số contrived A" trong cuộc gọi của chúng tôi. Cả hai hàm này đều có tham số đối tượng ẩn (đối với các hàm tĩnh mà tham số được sử dụng chỉ để nhận đối số đối tượng A). Tham số đối tượng ẩn của 'a' không tĩnh có kiểu' A & 'trong trường hợp của bạn (' A const & 'trong const member fncs). Đối số đối tượng contrived trong cuộc gọi 'A :: a()' khớp với cả hai tham số đối tượng ngầm, vì vậy bạn có một sự mơ hồ. –

+0

Vì vậy, điều này "contrived Một đối số đối tượng" là cùng loại như * này? – fang

3

Lý do là độ phân giải tên xảy ra trước bất kỳ trình biên dịch nào khác, như tìm ra chức năng quá tải để sử dụng.

Đủ điều kiện chức năng với A:: chỉ cần yêu cầu trình biên dịch "nhìn vào bên trong của A để tìm tên a". Nó không thực sự giúp giải quyết chức năng mà bạn đang đề cập đến.

EDIT

Và như vậy khi bạn gõ A::a(), đầu tiên trình biên dịch cho rằng "nhìn vào A cho một hàm thành viên hoặc thành viên những người có thể sử dụng operator()".

Sau đó trình biên dịch cho rằng, "Ok, hai khả năng ở đây, cái nào được nhắc đến? a() hoặc a(int c = 0) với một mặc định c=0. Không chắc.

Nếu bạn loại bỏ các từ khóa tĩnh và gọi là các chức năng như obj.a() , vẫn sẽ là một sự mơ hồ.

WRT phân tích cú pháp LLVM của

tôi sẽ nói rằng nó làm một số công việc bổ sung cho bạn, mà không được yêu cầu của tiêu chuẩn, đó sẽ là giả sử A::a() là tĩnh.

+0

Ai đó có thể trả lời tôi, điều đó có nghĩa là các hàm 'tĩnh', định nghĩa' tĩnh' là một phần của tên mangling, cho mục đích phân giải không? – Bingo

+0

Tôi không biết. Nhưng tên mangling là một vấn đề liên kết, không phải là một vấn đề trình biên dịch. –

+0

Bất kỳ thông tin chi tiết nào về lý do tại sao LLVM của Apple biên dịch tốt? Điều đó có nghĩa là trình phân tích cú pháp của LLVM có phân giải tên theo một số thứ tự khác không? – fang