2016-08-30 11 views
11

Các mã sau đây có thể được biên dịch mà không có lỗi:Tại sao `this` là một biểu thức phụ thuộc loại ngay cả khi lớp mẫu không có lớp cơ sở?

template <typename T> struct A { 
    void f() { this->whatever; } // whatever is not declared before 
}; 
int main() { 
    A<int> a; 
} 

Và tôi biết đó là vì this là một biểu thức kiểu phụ thuộc, mà làm cho tra cứu tên cho whatever được hoãn lại cho đến khi mẫu đối số thực tế được biết đến. Vì hàm thành viên f() không bao giờ được sử dụng trong trường hợp này, do đó không có instantiation nào của A<T>::f tồn tại và tra cứu tên cho whatever không bao giờ được thực hiện.

tôi có thể hiểu rằng this là loại phụ thuộc nếu mẫu lớp có một loại phụ thuộc vào cơ sở như:

template <typename T> struct B { T whatever; }; 
template <typename T> struct A : B<T> { 
    void f() { this->whatever; } 
}; 
int main() { 
    A<int> a; 
} 

Khi phân tích định nghĩa của lớp mẫu A, nó không thể biết loại cơ sở của nó là những gì , làm cho this->whatever có khả năng hợp pháp (B<T> có thể có thành viên có tên whatever). Ngược lại, tôi không thấy bất kỳ tiềm năng nào mà this->whatever sẽ là hợp pháp trong ví dụ đầu tiên ngay sau khi hàm thành viên f được sử dụng ở đâu đó.

Vì vậy, có thể this->whatever là hợp pháp tại một số điểm trong ví dụ đầu tiên? Nếu không, có bất kỳ lý do nào khác mà this nên được coi là biểu thức phụ thuộc vào loại trong trường hợp đó không?

+3

Trong trường hợp của bạn, loại 'this' này sẽ luôn là' A * const' trong 'A :: f()'. Tôi không hiểu nhầm lẫn của bạn. –

+3

@RSahu Tôi nghĩ câu hỏi đặt ra là tại sao ngôn ngữ định nghĩa 'this' là phụ thuộc vào kiểu trong bất kỳ ngữ cảnh mẫu nào, không chỉ là ngữ cảnh mà nó thực sự phụ thuộc vào kiểu. – templatetypedef

+1

@RSahu Tôi có nghĩa là nếu 'this' không được coi là phụ thuộc vào loại trong trường hợp đầu tiên, không nên nó ít bị lỗi? Theo hiểu biết của tôi, một trong những lý do mà không phụ thuộc tên là tra cứu khi phân tích cú pháp định nghĩa của mẫu thay vì khi instantiating mẫu là để làm cho mã ít dễ bị lỗi. – Carousel

Trả lời

4

Mã của bạn là "không đúng chuẩn, không cần chẩn đoán", vì không bao giờ có chuyên môn hợp lệ cho A::f. Trong thực tế, spec nói rằng this->whatever không phải là thành viên của một chuyên môn không xác định (vì không có lớp cơ sở phụ thuộc), cũng không phải là thành viên của phiên bản hiện tại (vì nó không được khai báo trong lớp cơ sở không phụ thuộc, cũng không phải trong lớp bản thân mẫu). Điều này ngoài ra làm cho mã của bạn không hợp lệ, và một lần nữa không có chẩn đoán là cần thiết (nhưng cho phép). Điều này được giải thích chi tiết hơn tại https://stackoverflow.com/a/17579889/34509

this phụ thuộc vào loại vì bạn chưa biết giá trị thông số mẫu trong định nghĩa. Vì vậy, ví dụ SomeOtherTemplate<decltype(*this)> không thể được giải quyết ngay lập tức, nhưng cần phải đợi cho đến khi mẫu lớp của this được khởi tạo (vì vậy bạn cần một typename trước SomeOtherTemplate<decltype(*this)>::type).

Tuy nhiên, chỉ vì this phụ thuộc vào loại, không có nghĩa là this->whatever là tốt. Như được mô tả ở trên, thông số kỹ thuật có các công cụ để phân loại chính xác điều này là không hợp lệ và trên thực tế cũng không không làm cho phụ thuộc loại this->whatever. Nó nói

A class member access expression ([expr.ref]) is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.

+0

Ồ, tôi học được rất nhiều từ câu trả lời này và liên kết. Cảm ơn rất nhiều! – Carousel

0

dụ của bạn có thể được đơn giản hóa hơn nữa:

template <typename T> struct A { 
    void f() { this = 1; } 
}; 
int main() { 
    A<int> a; 
} 

Tuyên bố this = 1; không bao giờ nên biên dịch và không thể được cố định ngay cả khi A<T> có một lớp cơ sở kiểu phụ thuộc. Tuy nhiên trình biên dịch không phàn nàn cho đến khi hàm A<T>::f() được khởi tạo.

Johannes Schaub - litb đã là answered đây có thể là tình huống "không cần chẩn đoán".

0

Đây là quy tắc tra cứu tên về tên phụ thuộc.

$14.6/9 Name resolution [temp.res]:

When looking for the declaration of a name used in a template definition, the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known ([temp.dep]).

Mục đích là, thông tin đó là không đủ nếu tên phụ thuộc vào tham số mẫu, cho đến khi mẫu đối số thực tế được biết đến. Người khiếu nại sẽ không phân biệt loại tên phụ thuộc (được hình thành bởi this hoặc những người khác), sẽ không kiểm tra các chi tiết như lớp có lớp cơ sở phụ thuộc hay không. Kết quả có thể không thay đổi như mã mẫu bạn đã hiển thị, nhưng nó chỉ trì hoãn việc tra cứu tên cho đến khi loại được biết, để đưa ra quyết định chính xác nhất.

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