2009-11-02 37 views
6

Tôi đã sau đoạn mã: trình biên dịchSử dụng hợp lệ hàm thành viên tĩnh của lớp mà không thể được cài đặt

Nó biên dịch không có vấn đề dưới gcc-3.4, gcc-4.3, intel, nhưng thất bại dưới MSVC9.

MSVC nói "sử dụng không xác định loại c_traits<C>, khi biên dịch lớp mẫu hàm thành viên void foo<C>::go(void) với C = ngắn.

Điểm nó trình biên dịch sẽ cố gắng để cài đặt chức năng thành viên không sử dụng các lớp không sử dụng, vì lớp này chỉ là không được sử dụng ở tất cả.

tôi có thể làm việc xung quanh vấn đề bằng cách chuyên toàn bộ foo lớp thay vì chuyên hàm thành viên của nó. Nhưng điểm nó mà chuyên toàn bộ lớp là một chút vấn đề đối với tôi vì những lý do khác nhau.

Câu hỏi lớn: điều gì là đúng?

  • là mã của tôi sai và gcc và intel trình biên dịch chỉ cần bỏ qua vấn đề này bởi vì họ không cài đặt foo đầy đủ, hoặc
  • Mã này là đúng và đây là lỗi của MSVC9 (VC 2008) mà nó cố gắng để cài đặt chức năng thành viên không được sử dụng?

Mã:

class base_foo { 
public: 
    virtual void go() {}; 
    virtual ~base_foo() {} 
}; 
template<typename C> 
struct c_traits; 

template<> 
struct c_traits<int> { 
    typedef unsigned int_type; 
}; 

template<typename C> 
class foo : public base_foo { 
public: 
    static base_foo *create() 
    { 
     return new foo<C>(); 
    } 
    virtual void go() 
    { 
     typedef typename c_traits<C>::int_type int_type; 
     int_type i; 
     i=1; 
    } 
}; 

template<> 
base_foo *foo<short>::create() 
{ 
    return new base_foo(); 
} 

int main() 
{ 
    base_foo *a; 
    a=foo<short>::create(); delete a; 
    a=foo<int>::create(); delete a; 
} 
+2

+1 cho mã đẹp, súc tích, có thể kết hợp. – GManNickG

Trả lời

3

Cả hai trình biên dịch đều ở ngay tại đây; hành vi cho trường hợp của bạn không được chỉ định. ISO C++ 14.7.1 [temp.inst]/9:

Việc triển khai sẽ không ngầm khởi tạo mẫu chức năng, mẫu thành viên, chức năng thành viên không phải ảo, lớp thành viên hoặc thành viên dữ liệu tĩnh của mẫu lớp không yêu cầu khởi tạo. Nó không được chỉ định có hay không thực hiện ngầm định một hàm thành viên ảo của một mẫu lớp nếu hàm thành viên ảo sẽ không được khởi tạo.

Lý do cho điều này khá đơn giản: một hàm ảo yêu cầu mục nhập vtable, và với công văn ảo, trình biên dịch có thể khó xác định xem chức năng ảo thực sự có được gọi hay không. Do đó, ISO C++ cho phép các trình biên dịch thực hiện phân tích nâng cao để tạo ra mã nhỏ hơn, nhưng không yêu cầu nó - vì vậy, như một lập trình viên C++, bạn nên luôn luôn giả định rằng tất cả các hàm ảo sẽ luôn được khởi tạo.

+1

Điều đó sẽ dạy tôi dừng lại ở đoạn 3 của bất cứ điều gì. –

+0

Vâng, bạn phải dừng đâu đó :) nhưng có thể tệ hơn - đôi khi trong C++ bạn nhận được một đoạn đặc biệt nói như vậy và như vậy trong phần, nói, 15.2, và sau đó nó chỉ ra rằng có một đoạn khác làm thay đổi những quy tắc một cách tinh tế ở đâu đó 3.7 (với tham chiếu về phía trước). Nó gần như đánh bại các sách quy tắc D & D. –

+0

Ok cảm ơn. Vì vậy, mã của tôi là sai;) – Artyom

1

Việc loại bỏ các chức năng không sử dụng sẽ xảy ra ở nối không phải ở biên soạn nơi bạn đang gặp lỗi của bạn. MSVC có thể không biết ai trong số tất cả các đơn vị biên dịch được biên dịch, người cuối cùng sẽ gọi phương thức đó. Nó không thể biết cho đến khi biên dịch hoàn tất và cho đến khi liên kết xảy ra. Trình biên dịch tự nhiên khác nhau có thể thông minh hơn về điều này, nhưng tôi nghi ngờ điều này có thể là những gì đang xảy ra.

tôi nghi ngờ lỗi biên dịch cụ thể của bạn có vẻ như nó được gây ra bởi bạn chỉ có phía trước tuyên bố

template<typename C> 
struct c_traits; 

bạn chưa quy định đầy đủ các lớp học. Bạn đã thử một cái gì đó đơn giản như:

template<typename C> 
struct c_traits 
{ 
    // some default/dummy int type 
}; 

Tôi nghi ngờ điều này ít nhất sẽ ngăn trình biên dịch khỏi phàn nàn.

EDIT

này nói chung là sai cho lớp mẫu. Các hàm thành viên của lớp mẫu không được coi là biên soạn (và bất kỳ sai sót trong cơ quan của họ không được coi là kích hoạt) trừ khi chúng instantiated

Các mẫu được thuyết minh trong trường hợp này trong biểu mẫu của:

foo<short> 

Trình biên dịch sẽ coi đây là bất kỳ lớp nào khác là phương pháp có tiềm năng liên kết bên ngoài.Tôi chưa nghe bất kỳ quy tắc ngôn ngữ đặc biệt nào nói rằng liên kết bên ngoài không áp dụng cho các mẫu ...?

+0

Anh ta phàn nàn rằng trình biên dịch thậm chí còn đang cố biên dịch phương thức ảo, vì anh ta không gọi phương thức này, và không khởi tạo lớp. –

+0

Tôi đã thử những gì bạn đề nghị: nhưng nó phàn nàn rằng 'int_type' không xác định. – Artyom

+0

@Artyom: Tôi nghĩ rằng Doug có nghĩa là bạn nên cung cấp một typedef giả nơi bình luận của ông là: mẫu c_traits struct { \t typedef int int_type; }; – Eclipse

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