Khước từ
đây không phải là một câu trả lời, mà là một bình luận dài
Kỹ năng luật sư ngôn ngữ của tôi quá thấp để có thể hiểu đầy đủ về tiêu chuẩn nhưng đây là một vài điều tôi phát hiện ra khi thử nghiệm mã. Tất cả mọi thứ tiếp theo đều dựa trên sự hiểu biết (không hoàn hảo) của tôi về vấn đề này và có lẽ cần một số đánh giá.
Cuộc điều tra
Trước hết, tôi đã đi đến một phiên bản tiêu chuẩn được xác định đầy đủ (C ++ 17) để chúng tôi hoạt động trên một triển khai được xác định rõ.
Nhìn vào mã này, có vẻ như MSVC vẫn còn một số vấn đề (với việc tra cứu, tôi đoán vậy?) Khi nói đến việc khởi tạo và xác định lại mẫu. Tôi sẽ không tin MSVC nhiều trong kịch bản của chúng tôi.
Điều đó nói rằng, hãy nghĩ về lý do tại sao chúng ta có thể cần templatetừ khóa tại
return yF.template head<1>();
Tên người phụ thuộc
Đôi khi, bên trong các mẫu, chúng ta phải giúp trình biên dịch quyết định xem tên có đề cập đến
- một giá trị
int T::x = 0,
- một loại
struct T::x {};, hoặc
- một mẫu
template <typename U> T::foo<U>();
Nếu chúng ta đề cập đến một giá trị, chúng ta không làm gì cả. Nếu chúng ta đề cập đến một loại, chúng ta phải sử dụng typename. Và nếu chúng ta đề cập đến một mẫu chúng ta sử dụng template. Thêm về chủ đề đó có thể được tìm thấy ở đây .
Tôi không hiểu đặc điểm kỹ thuật tiêu chuẩn khi nói đến định nghĩa thực tế của tên phụ thuộc nhưng đây là một số quan sát.
Quan sát
Hãy xem mã tham chiếu
template <int N>
struct Matrix
{
template <int Idx>
int head() { return Idx; }
};
template <typename T>
struct Test
{
static constexpr int RayDim = 3;
int func() const
{
Matrix<RayDim> yF;
return yF.head<1>(); // clang complains, gcc and msvc are ok
}
};
struct Empty {};
int test()
{
Test<Empty> t;
return t.func();
}
Thông thường RayDimnên là một tên phụ thuộc (vì nó nằm trong mẫu Test) sẽ gây ra Matrix<RayDim>một tên phụ thuộc. Bây giờ, hãy giả sử rằng Matrix<RayDim>thực sự là một tên phụ thuộc. Điều này làm cho Matrix<RayDim>::headmột tên phụ thuộc là tốt. Vì Matrix<RayDim>::headlà một hàm templated, bản thân nó là một khuôn mẫu và quy tắc của các tên phụ thuộc từ bên trên áp dụng, yêu cầu chúng tôi sử dụng templatetừ khóa. Đây là những gì clang đang phàn nàn về.
Tuy nhiên, vì RayDimđược định nghĩa bên trong Testvà funccũng được định nghĩa bên trong cùng một khuôn mẫu và bản thân nó không phải là một hàm templated, tôi không nghĩ RayDimthực sự là một tên phụ thuộc trong ngữ cảnh func. Hơn nữa, RayDimkhông dựa vào các đối số mẫu của Test. Trong trường hợp này, Matrix<RayDim>và Matrix<RayDim>::headtương ứng, sẽ trở thành tên không phụ thuộc, cho phép chúng ta bỏ qua templatetừ khóa. Đây là lý do tại sao gcc (và msvc) biên dịch.
Nếu chúng ta đã mẫu như RayDimlà tốt, như ở đây
template <typename>
static constexpr int RayDim = 3;
gcc sẽ coi nó như một tên phụ thuộc aswell (điều này là chính xác, vì có thể có một chuyên môn mẫu sau này vì vậy chúng tôi không biết tại thời điểm đó). Trong khi đó, msvc vui vẻ chấp nhận mọi thứ chúng tôi ném vào nó.
Phần kết luận
Có vẻ như nó đang sôi sục cho dù RayDimlà một tên phụ thuộc trong bối cảnh Test<T>::funchay không. Clang nghĩ rằng nó là, gcc không. Từ một số thử nghiệm khác, nó trông giống như các mặt msvc với tiếng kêu trên cái này. Nhưng đó cũng là việc làm của riêng nó, vậy ai biết?
Tôi sẽ đứng về phía gcc ở đây vì tôi thấy không có cách nào có thể RayDimtrở nên phụ thuộc vào thời điểm funcđược khởi tạo.