2009-03-08 55 views
8

Tôi đang biên soạn một thư viện tĩnh C++ và vì tất cả các lớp đều được tạo khuôn mẫu, các định nghĩa lớp và các triển khai đều nằm trong các tệp tiêu đề. Kết quả là, có vẻ như (theo visual studio 2005) mà tôi cần tạo một tệp .cpp bao gồm tất cả các tệp tiêu đề khác để nó biên dịch chính xác vào thư viện.Biên dịch C++ .lib chỉ với các tệp tiêu đề?

Tại sao điều này?

Trả lời

8

Trình biên dịch không biên dịch tệp tiêu đề vì các tệp này có nghĩa là được đưa vào tệp nguồn. Trước khi bất kỳ trình biên dịch nào diễn ra, bộ tiền xử lý sẽ lấy tất cả mã từ bất kỳ tệp tiêu đề được bao gồm nào và đặt mã đó vào các tệp nguồn mà chúng được bao gồm, tại chính địa điểm chúng được bao gồm. Nếu trình biên dịch cũng nên biên dịch headerfiles, ví dụ bạn có nhiều định nghĩa về nhiều thứ.

Ví dụ, đây là những gì Preprocessor thấy:

[foo.h] 
void foo(); 

-

[mysource.cpp] 
#include "foo.h" 

int main() 
{ 
    foo(); 
} 

Và đây là những gì các trình biên dịch thấy:

[mysource.cpp] 
void foo(); 

int main() 
{ 
    foo(); 
} 
0

Hãy suy nghĩ về Thư viện mẫu chuẩn. Các lớp khuôn mẫu của bạn sẽ được biên dịch khi bạn sử dụng chúng trong một dự án khác.

0

Những gì người khác đã nói là đúng về các mẫu không được biên dịch vào thư viện. Tuy nhiên, nó vẫn còn có giá trị buộc họ phải được nhìn thấy bởi trình biên dịch (bằng cách bao gồm chúng trong một tập tin .cpp) như cách này họ ít nhất sẽ được kiểm tra cú pháp.

+0

Bạn nên viết một tập hợp các bài kiểm tra đơn vị hơn bằng cách buộc tạo một thư viện tĩnh không cần tồn tại. Sau khi tất cả, nhiều trình biên dịch sẽ bỏ lỡ các lỗi rất cơ bản trên mã mẫu nếu mã mẫu đó không được gọi. – Tom

2

Trong C++, mẫu chỉ là định nghĩa meta của một lớp thực tế. Khi bạn biên dịch một lớp templated, trình biên dịch thực sự tạo ra mã cho lớp thực tế đang chạy cho loại dữ liệu cụ thể được truyền vào (mẫu chỉ là một "mẫu" để sao chép).

ví dụ: Nếu bạn có các mã sau

 

struct MyTemplate 
{ 
private: 
    float MyValue; 

public: 
    float Get() { return MyValue; } 
    void Set(float value) { MyValue = value; } 
}; 

void main() 
{ 
    MyTemplate v1; 
    MyTemplate v2; 
    v1.Set(5.0f); 
    v2.Set(2); 
    v2.Get(); 
} 
 

gì trình biên dịch thực sự thấy là

 

struct CompilerGeneratedNameFor_MyTemplate_float 
{ 
private: 
    float MyValue; 

public: 
    float Get() { return MyValue; } 
    void Set(float value) { MyValue = value; } 
}; 

struct CompilerGeneratedNameFor_MyTemplate_int 
{ 
private: 
    int MyValue; 

public: 
    int Get() { return MyValue; } 
    void Set(int value) { MyValue = value; } 
}; 

void main() 
{ 
    CompilerGeneratedNameFor_MyTemplate_float v1; 
    CompilerGeneratedNameFor_MyTemplate_int v2; 
    v1.Set(5.0f); 
    v2.Set(2); 
    v2.Get(); 
} 
 

Như bạn có thể thấy, trình biên dịch không thực sự biết những gì mã để tạo ra, cho đến khi bạn thực sự tuyên bố một thể hiện của mẫu của bạn. Điều này có nghĩa rằng mẫu không thể được biên dịch thành một thư viện, bởi vì nó không biết những gì các mẫu thực sự sẽ được kết thúc. Tin tốt về điều này là bạn không thực sự cần bất kỳ thư viện nào được biên soạn hoặc đưa vào nếu bạn chỉ phân phối các tệp tiêu đề có chứa định nghĩa mẫu.

Ngoài ra, như một lưu ý phụ, lệnh 'biên soạn trước' #include 'thực sự chỉ yêu cầu trình biên dịch trước thay thế' #include 'bằng mọi thứ từ tệp đó.

1

Bạn đang cố gắng tạo thứ gì đó không cần thiết. Hầu hết các thư viện C (và tất cả các thư viện C++) được phân phối như hai phần:

  • Interface (foo.h)
  • thực hiện (foo.lib)

Đối với C++ mẫu mã, tất cả các thư viện của bạn phải được biên dịch bởi người dùng cuối của bạn, bởi vì đó là cách các mẫu hoạt động. Không có lý do gì để cung cấp một thư viện được biên dịch trước. Trong trường hợp này, bạn có thể nghĩ đến phân phối thư viện của bạn như thế này:

  • Interface (foo.h)
  • thực hiện (foo-inl.h)

Như Niel đã nói ở trên, nó là hữu ích để có việc thực hiện chỉ dành riêng cho bạn mục đích thử nghiệm của riêng mình và có thể phân phối những thứ đó với chính thư viện. Vì vậy, bạn nên có một bộ thử nghiệm đơn vị riêng biệt thực hiện mã của bạn; nhưng những bài kiểm tra đó không nên là một phần của chính thư viện.

0

Bạn không cần phải tạo một .lib nếu tất cả các lớp của bạn là mẫu, hãy xem tăng hoặc stlport chúng không có .lib mà chúng phân phối [1].

Mẫu được biên dịch khi chúng được sử dụng. Nghiêm túc nói rằng họ phân phối các thư viện cho các tính năng nâng cao hơn như biểu thức thông thường, iostream, vv, nhưng các thư viện phụ được sử dụng bởi các mẫu khác, bản thân các mẫu không được phân phối dưới dạng thư viện.

2

Nếu tất cả mã của bạn nằm trong tệp .h, thì bạn không cần biên dịch một thư viện tĩnh để sử dụng mã.

Tất cả các mã có sẵn để sử dụng thư viện tại thời gian biên dịch, vì vậy không có gì là cần thiết tại thời gian liên kết.

1

Nếu thư viện của bạn được triển khai tất cả trong tệp tiêu đề, bạn không cần phải xây dựng bất kỳ nhị phân nào để sử dụng nó. Mà nói. Tôi thường tạo một file .cpp trong giai đoạn phát triển ban đầu của thư viện header. Tại sao? Trình biên dịch không cố gắng biên dịch hoặc thậm chí phân tích mẫu của bạn cho đến khi nó thực sự được sử dụng. Có một tệp .cpp và có một số mã giả ở đó để khởi tạo các mẫu giúp tôi tìm lỗi cú pháp trước đó trong quá trình phát triển. Vì vậy, tôi có thể thêm một số mã mẫu, nhấn biên dịch, sửa lỗi cú pháp, thêm mã, biên dịch ... v.v. Nếu bạn cố gắng tìm kiếm một số lỗi cú pháp ngớ ngẩn sau khi thêm hàng trăm dòng mã, bạn sẽ biết ý tôi là gì. Khi thư viện của tôi đã sẵn sàng cho bài kiểm tra đơn vị, tôi sẽ xóa tệp .cpp và dựa vào các đơn vị tinh hoàn để thúc đẩy sự phát triển của tôi.

Ngoài ra, nếu bạn chỉ biên dịch mã của bạn bằng VC++, một điều bạn cần biết là VC++ không cố biên dịch tất cả các hàm thành viên mẫu cho đến khi nó thực sự được sử dụng. Ví dụ:

template <typename T> 
class MyTemplate 
{ 
public: 
    MyTemplate() {} // default constructor 

    MyTemplate(int) { 
     1 = 2 
     // other syntax error code here 
    } 
}; 

void f() { MyTemplate<int> myt(); } // compile fine in VC 
void g() { MyTemplate<int> myt(1); } // syntax error 

F() sẽ biên dịch tốt với VC++ 2003, g ++ sẽ phát hiện lỗi cú pháp. Tôi nghĩ rằng VC8 và VC9 cũng có cùng một vấn đề.

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