Clang có đúng để từ chối mã trong đó lớp lồng của mẫu lớp chỉ được xác định thông qua các chuyên ngành không?


17

Cho mẫu lớp sau:

template<typename T>
struct Outer
{
    struct Inner;

    auto f(Inner) -> void;
};

chúng tôi xác định Innerriêng cho từng chuyên ngành của Outer:

template<>
struct Outer<int>::Inner {};

template<>
struct Outer<double>::Inner {};

và sau đó xác định hàm thành viên fmột lần cho tất cả các chuyên ngành Outer:

auto Outer<T>::f(Inner) -> void
{

}

nhưng Clang (9.0.0) phàn nàn:

error: variable has incomplete type 'Outer::Inner'

auto Outer<T>::f(Inner) -> void

                      ^

Chúng tôi có thể tránh lỗi trình biên dịch bằng cách cung cấp định nghĩa Innercho tất cả các chuyên ngành khác về Outer:

template<typename T>
struct Outer<T>::Inner {};

hoặc bằng cách định nghĩa friêng cho từng chuyên ngành:

template<>
auto Outer<int>::f(Inner) -> void
{

}

template<>
auto Outer<double>::f(Inner) -> void
{

}

Cả GCC và MSVC đều chấp nhận mã ban đầu, điều này đặt ra câu hỏi; Đây có phải là lỗi Clang hay đây là cách thực hiện phù hợp duy nhất trong số ba?

Thử trên Trình biên dịch Explorer


Các chuyên ngành của Nội bộ không liên quan, loại bỏ chúng không làm thay đổi kết quả biên dịch.
n. 'đại từ' m.

@ n.'pronouns'm. Tôi không chắc ý của bạn là gì. Cả việc thêm một định nghĩa Innercho tất cả các chuyên ngành khácđịnh nghĩa friêng cho từng chuyên môn đều giải quyết lỗi biên dịch.
khai báo

Chúng ta hãy đọc lại: loại bỏ chúng không làm thay đổi kết quả biên dịch . Không thêm, xóa. gcc clang
n. 'đại từ' m.

@ n.'pronouns'm. Tôi hiểu ý của bạn bây giờ, nhưng đó vẫn là một nhận xét lạ. Điểm của câu hỏi của tôi Innerlà được báo cáo là một loại không đầy đủ mặc dù các định nghĩa cho mỗi chuyên ngành Outerđược cung cấp. Rõ ràng Innersẽ (chính xác) là một loại không đầy đủ nếu bạn loại bỏ định nghĩa của nó.
khai báo

"Rõ ràng Nội sẽ (chính xác) là một loại không đầy đủ nếu bạn loại bỏ định nghĩa của nó (s)." No rằng "không phải ở tất cả ckear Một chuyên môn là một mẫu hoàn toàn riêng biệt và nó không ảnh hưởng đến mẫu chính ở tất cả..
n. 'đại từ' m.

Câu trả lời:


4

Tôi tin rằng Clang đã sai khi từ chối mã của bạn. Chúng ta phải tự hỏi, làm thế nào để khai báo và định nghĩa hàm của bạn so với

auto f(typename T::Inner) -> void;

// ...

template<typename T>
auto Outer<T>::f(typename T::Inner) -> void
{ }

Trong ví dụ này, T::Innerrõ ràng là một loại phụ thuộc. Vì vậy, Clang có thể không cho rằng nó không đầy đủ cho đến khi khởi tạo. Điều tương tự có đúng trong ví dụ của bạn không? Tôi sẽ nói như vậy. Đối với chúng tôi có điều này trong tiêu chuẩn:

[temp.dep.type]

5 Tên là thành viên của khởi tạo hiện tại nếu có

  • Một tên không đủ tiêu chuẩn, khi được tra cứu, đề cập đến ít nhất một thành viên của một lớp là khởi tạo hiện tại hoặc một lớp cơ sở không phụ thuộc. [Lưu ý: Điều này chỉ có thể xảy ra khi tra cứu tên trong phạm vi kèm theo định nghĩa của mẫu lớp. - lưu ý cuối]
  • ...

Tên là thành viên phụ thuộc của khởi tạo hiện tại nếu nó là thành viên của khởi tạo hiện tại, khi nhìn lên, đề cập đến ít nhất một thành viên của một lớp là khởi tạo hiện tại.

9 Một loại phụ thuộc nếu nó là

  • ...
  • một thành viên của một chuyên ngành chưa biết,
  • một lớp lồng nhau hoặc liệt kê là một thành viên phụ thuộc của khởi tạo hiện tại,
  • ...

Vì vậy, viên đạn đầu tiên trong đoạn 9 bao gồm trường hợp typename T::Inner. Đó là một loại phụ thuộc.

Trong khi đó trường hợp của bạn được bao phủ bởi viên đạn thứ hai. Outer::Innerlà một cái tên được tìm thấy trong phần khởi tạo hiện tại Outer, hơn nữa nó được tìm thấy bên trong Outerchính nó chứ không phải trong một lớp cơ sở. Điều đó làm cho nó trở thành một thành viên phụ thuộc của việc khởi tạo hiện tại. Tên này đề cập đến một lớp lồng nhau. Có nghĩa là tất cả các điều kiện trong viên đạn thứ hai được áp dụng, do đó cũng tạo ra Outer::Innermột loại phụ thuộc!

Vì chúng ta có một loại phụ thuộc trong cả hai trường hợp, trình biên dịch nên coi chúng là loại phụ thuộc. Kết luận của tôi là GCC và MSVC là đúng.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.