2015-09-01 21 views
8

Xét đoạn mã sau:Tại sao tuyên bố này của một hàm trong lớp mẫu không hợp lệ?

template<int X, int Y> 
struct S 
{ 
    typedef int func(int,float) const; 
}; 

template<int X> 
struct D : public S<X,6> 
{ 
    typename S<X,6>::func func; 
}; 
template<int X> 
int D<X>::func(int,float) const 
{ 
    return 1; 
} 
//---------------- 
struct W : public S<7,8> 
{ 
    S<7,8>::func func; 
}; 
int W::func(int,float) const 
{ 
    return 2; 
} 

#include <iostream> 
int main() 
{ 
    W w; 
    std::cout << w.func(1,4.3) << "\n"; 
    D<3> d; 
    std::cout << d.func(1,4.3) << "\n"; 
} 

Nếu tôi nhận xét ra mã khai báo lớp DD::func() cũng như các dòng tương ứng trong main(), mã biên dịch bình thường, và tôi thấy 2 trong đầu ra, như mong đợi.

Nhưng khi tôi làm cho lớp mẫu có nguồn gốc (thêm typename trước khi khai báo hàm, như S<X.6> là một phạm vi phụ thuộc), tôi nhận được các lỗi sau đây:

test.cpp:13:27: error: no ‘int D<X>::func(int, float) const’ member function declared in class ‘D<X>’ 
int D<X>::func(int,float) const 
         ^
test.cpp: In instantiation of ‘struct D<3>’: 
test.cpp:32:10: required from here 
test.cpp:10:27: error: field ‘D<3>::func’ invalidly declared function type 
    typename S<X,6>::func func; 
         ^
  • Tại sao tôi không thể tuyên bố func trong một lớp mẫu có nguồn gốc, trong khi trong lớp không mẫu nó là OK?
  • Chính xác "loại chức năng được khai báo không hợp lệ" là gì? những gì không hợp lệ ở đây?
+0

Tôi có cảm giác rằng điều này về mặt kỹ thuật hợp lệ bởi [dcl.fct]/10 trong thông số kỹ thuật, nhưng tuyên bố một hàm có typedef phụ thuộc giống như trường hợp góc của trường hợp góc: Tôi không chắc liệu có trình biên dịch nào hay không sẽ xử lý nó như bạn mong đợi. – TartanLlama

+0

Tôi sẽ nói rằng 'S ' có thể được chuyên biệt sau này, do đó, định nghĩa của 'D :: func' có thể trở thành không hợp lệ. – Jarod42

+0

@ Jarod42 Có vẻ như chúng ta cần 'function_typename' cũng như' typename': p – TartanLlama

Trả lời

3

N3337 [dcl.fct]/10: A typedef loại hàm có thể được sử dụng để khai báo hàm nhưng không được dùng để xác định hàm.

Theo quy tắc này, cả hai DW đều được hình thành kỹ thuật. Tôi nghĩ rằng lý do này không biên dịch với GCC hoặc Clang là tuyên bố một chức năng với typedef thực sự là hiếm. Khai báo một hàm với một typedef thành viên phụ thuộc vào tham số mẫu thậm chí còn hiếm hơn. Có vẻ như bạn vừa mới nhấn vào một góc tối nơi hỗ trợ trình biên dịch bị hạn chế.

Funnily đủ, MSVC thực sự does the right thing tại đây.

Tùy chọn tốt nhất của bạn có thể là tìm cách khác để thể hiện các lớp học của bạn. Tôi thực sự không thể đưa ra lời khuyên nào mà không biết thêm về vấn đề bạn đang cố giải quyết, nhưng nếu bạn hỏi một câu hỏi mới, chúng tôi có thể đưa ra một số gợi ý.

Bạn cũng có thể nghĩ đến việc gửi báo cáo lỗi cho GCCClang.


Edit:

Tuy nhiên, như Jarod42 chỉ ra, các loại phụ thuộc có thể sau đó được định nghĩa là một cái gì đó khác hơn là một loại chức năng, đưa ra tuyên bố không hợp lệ. Lý do MSVC hoạt động mà GCC và Clang không phải là lý do tương tự MSVC không yêu cầu typename ở một số nơi: nó không thực hiện đúng hai giai đoạn tra cứu. Có trường hợp này được chỉ định đầy đủ sẽ yêu cầu một cái gì đó như function_typename để đánh dấu một tên phụ thuộc như là một loại chức năng. Tôi nghĩ rằng việc khai báo một hàm dựa trên kiểu phụ thuộc là không được xác định và không nhất quán như là kết quả của việc này là một trường hợp rất hiếm.

+2

Ngay cả 'function_typename' là không đủ có chữ ký có thể khác với định nghĩa (hoặc sẽ yêu cầu một định nghĩa mới cho chuyên môn). – Jarod42

+0

@ Jarod42 Bạn nói đúng, nó cần phải nêu rõ chữ ký mà typedef đại diện, điều này hoàn toàn phá hủy toàn bộ điểm làm việc này ngay từ đầu. – TartanLlama

+0

Tại sao điều này lại là một vấn đề, rằng một chuyên môn làm mất hiệu lực tờ khai? Có giả thiết rằng tờ khai là hợp lệ, mà không phải là bị hỏng sau một số điểm? – Ruslan

0

Khi thông báo lỗi nêu rõ: Trong Dfunc không phải là chức năng của thành viên, do đó bạn không thể cung cấp định nghĩa cho nó. Nó là một thành viên với loại S<X,6>::func.

+2

Nhưng nó hoạt động với 'W'. – Ruslan

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