2010-09-20 37 views
37

Tại sao việc triển khai và khai báo một lớp mẫu phải nằm trong cùng một tệp tiêu đề? Có thể nào bạn giải thích nó bằng ví dụ?Tại sao việc triển khai và khai báo một lớp mẫu phải nằm trong cùng một tệp tiêu đề?

+7

chúng phải hiển thị trong cùng một đơn vị biên dịch.chúng có thể nằm trong các tệp khác nhau nếu cả hai được bao gồm – Anycorn

+2

Thực tế không phải là không phổ biến để phân tách khai báo và triển khai trong hai tệp. Tiêu đề sẽ thường bao gồm tệp triển khai. – MSalters

+0

@MSalters: Đó là vấn đề với các lớp mẫu, đó là những gì câu hỏi này là về. Tôi ước gì tôi có thể bình luận. –

Trả lời

24

Trình biên dịch cần phải có quyền truy cập vào toàn bộ định nghĩa mẫu (không chỉ chữ ký) để tạo mã cho mỗi phiên bản mẫu, vì vậy bạn cần phải di chuyển định nghĩa của hàm vào tiêu đề của mình.

Để biết thêm chi tiết, hãy đọc về The Inclusion Model.

+1

Không, bạn không biết. nhưng tất nhiên quy tắc tiêu đề được thiết kế để giúp bạn tránh những điều vô nghĩa như vậy. :) –

+0

@LightnessRacesinOrbit Tôi có thể hỏi TU là gì? – athos

+0

@athos http://en.wikipedia.org/wiki/Translation_unit_%28programming%29 –

6

Định nghĩa của một mẫu lớp và việc thực hiện các chức năng thành viên của nó phải được hiển thị cho mọi nơi tạo ra nó với một kiểu riêng biệt. tức là để khởi tạo myTemplate<int>, bạn cần xem định nghĩa đầy đủ và cách triển khai myTemplate.

Cách dễ nhất để thực hiện việc này là đặt định nghĩa mẫu và chức năng thành viên của nó vào cùng một tiêu đề, nhưng có nhiều cách khác. Ví dụ: bạn có thể đặt các triển khai hàm thành viên trong một tệp riêng biệt được bao gồm riêng biệt. Sau đó, bạn có thể bao gồm nó từ tiêu đề đầu tiên hoặc chỉ bao gồm tệp triển khai nơi bạn cần.

Ví dụ: một thực hành là khởi tạo rõ ràng mẫu cho tập hợp tham số riêng biệt trong một tệp .cpp và khai báo những sự kiện đó extern trong tiêu đề. Bằng cách này, các instantiations đó có thể được sử dụng trong các tệp nguồn khác mà không yêu cầu thực hiện các hàm thành viên mẫu để hiển thị. Tuy nhiên, trừ khi bạn bao gồm tệp triển khai, bạn sẽ không thể sử dụng các bộ tham số mẫu khác.

ví dụ: nếu bạn có myTemplate<int>myTemplate<std::string> định nghĩa là extern sau đó bạn có thể sử dụng chúng tốt, nhưng nếu myTemplate<double> không được định nghĩa extern thì bạn không thể sử dụng mà không thực hiện.

4

Trong trường hợp của một lớp bình thường, bản khai chỉ đủ để biên dịch và các định nghĩa tương ứng sẽ là được liên kết.

Trong trường hợp mẫu, trình biên dịch cũng cần định nghĩa để tạo mã.

Sự khác biệt được giải thích rõ hơn trong số C++ FAQ.

4

Họ không phải làm như vậy.

Điều cần thiết là định nghĩa mẫu hiển thị tại điểm diễn giải (nơi nó được sử dụng) để trình biên dịch có thể lấy được lớp/hàm từ mẫu tại thời điểm này.

Tuy nhiên nó là rất phổ biến để sử dụng hai tập tin tiêu đề cho mẫu lớp:

// foo_fwd.hpp 
template <typename T, typename U> struct Foo; 

// foo.hpp 
#include "foo_fwd.hpp" 

template <typename T, typename U> struct Foo { typedef std::pair<T,U> type; }; 

Điều này cho phép những người không cần mẫu định nghĩa đầy đủ bao gồm đầu trang có phần nhẹ hơn, ví dụ:

//is_foo.hpp 
#include <boost/mpl/bool.hpp> 
#include "foo_fwd.hpp" 

template <typename Z> 
struct is_foo: boost::mpl::false_ {}; 

template <typename T, typename U> 
struct is_foo< Foo<T,U> >: boost::mpl::true_ {}; 

có thể tăng tốc độ biên dịch một chút.

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