Câu hỏi Tại sao các mẫu chỉ có thể được triển khai trong tệp tiêu đề?


Trích dẫn từ Thư viện chuẩn C ++: hướng dẫn và sổ tay:

Cách di động duy nhất để sử dụng các mẫu tại thời điểm này là triển khai chúng trong các tệp tiêu đề bằng cách sử dụng các hàm nội dòng.

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

(Làm rõ: tệp tiêu đề không phải là chỉ có giải pháp di động. Nhưng chúng là giải pháp di động thuận tiện nhất.)


1386
2018-01-30 10:06


gốc


Câu hỏi không đúng. Có một cách di động khác. Lớp mẫu có thể được khởi tạo rõ ràng - như đã được chỉ ra bởi các câu trả lời khác. - Aaron McDaid
Mặc dù việc đặt tất cả các định nghĩa hàm mẫu vào tệp tiêu đề có lẽ là cách thuận tiện nhất để sử dụng chúng, nhưng vẫn không rõ ràng "nội tuyến" đang làm gì trong báo giá đó. Không cần sử dụng các hàm nội tuyến cho điều đó. "Inline" hoàn toàn không liên quan gì đến điều này. - AnT
Sách đã lỗi thời. - gerardw


Các câu trả lời:


Nó là không phải cần thiết để thực hiện trong tệp tiêu đề, xem giải pháp thay thế ở cuối câu trả lời này.

Dù sao, lý do mã của bạn là thất bại là, khi instantiating một mẫu, trình biên dịch tạo ra một lớp mới với các đối số mẫu nhất định. Ví dụ:

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f; 

Khi đọc dòng này, trình biên dịch sẽ tạo một lớp mới (hãy gọi nó là FooInt), tương đương với những điều sau đây:

struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

Do đó, trình biên dịch cần phải có quyền truy cập vào việc thực hiện các phương thức, để khởi tạo chúng với đối số mẫu (trong trường hợp này) int). Nếu những triển khai này không có trong tiêu đề, chúng sẽ không thể truy cập được, và do đó trình biên dịch sẽ không thể khởi tạo mẫu.

Một giải pháp chung cho việc này là viết khai báo mẫu trong một tệp tiêu đề, sau đó triển khai lớp trong tệp triển khai (ví dụ .tpp) và bao gồm tệp triển khai này ở cuối tiêu đề.

// Foo.h
template <typename T>
struct Foo
{
    void doSomething(T param);
};

#include "Foo.tpp"

// Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}

Bằng cách này, việc triển khai vẫn được tách ra khỏi khai báo, nhưng có thể truy cập được tới trình biên dịch.

Một giải pháp khác là giữ cho việc triển khai được tách biệt và nhanh chóng khởi tạo tất cả các cá thể mẫu mà bạn sẽ cần:

// Foo.h

// no implementation
template <typename T> struct Foo { ... };

//----------------------------------------    
// Foo.cpp

// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

Nếu lời giải thích của tôi không đủ rõ ràng, bạn có thể xem C ++ Super-FAQ về chủ đề này.


1208
2018-01-30 10:26



Trên thực tế, instantiation rõ ràng cần phải ở trong một tệp .cpp có quyền truy cập vào các định nghĩa cho tất cả các hàm thành viên của Foo, chứ không phải trong tiêu đề. - Mankarse
"trình biên dịch cần phải có quyền truy cập vào việc thực hiện các phương thức, để khởi tạo chúng với đối số mẫu (trong trường hợp này int). Nếu các triển khai này không có trong tiêu đề, chúng sẽ không thể truy cập được" tệp .cpp không thể truy cập được vào trình biên dịch? Một trình biên dịch cũng có thể truy cập thông tin .cpp, cách khác nó sẽ biến chúng thành tệp .obj? EDIT: câu trả lời cho câu hỏi này là trong liên kết được cung cấp trong câu trả lời này ... - xcrypt
Tôi không nghĩ rằng điều này giải thích câu hỏi rõ ràng, điều quan trọng rõ ràng là liên quan đến UNIT biên soạn mà không được đề cập trong bài viết này - zinking
@Gabson: các cấu trúc và các lớp tương đương với ngoại lệ là trình sửa đổi truy cập mặc định cho các lớp là "riêng tư", trong khi nó là công khai cho các cấu trúc. Có một số khác biệt nhỏ khác mà bạn có thể học bằng cách xem câu hỏi này. - Luc Touraille
Sử dụng instantiation rõ ràng nếu không bạn sẽ nhận được rất chậm xây dựng sớm .. - Nils


Rất nhiều câu trả lời đúng ở đây, nhưng tôi muốn thêm câu trả lời này (để hoàn thành):

Nếu bạn, ở dưới cùng của tập tin cpp thực hiện, làm rõ ràng instantiation của tất cả các loại mẫu sẽ được sử dụng với, các mối liên kết sẽ có thể tìm thấy chúng như bình thường.

Chỉnh sửa: Thêm ví dụ về việc khởi tạo mẫu rõ ràng. Được sử dụng sau khi mẫu đã được xác định và tất cả các hàm thành viên đã được xác định.

template class vector<int>;

Điều này sẽ khởi tạo (và do đó tạo sẵn cho trình liên kết) lớp và tất cả các hàm thành viên của nó (chỉ). Cú pháp tương tự hoạt động với các hàm mẫu, vì vậy nếu bạn có quá tải toán tử không phải thành viên, bạn có thể cần phải thực hiện tương tự cho các hàm đó.

Ví dụ trên là khá vô ích vì vector được xác định đầy đủ trong các tiêu đề, ngoại trừ khi một tệp bao gồm chung (tiêu đề được biên dịch trước?) Sử dụng extern template class vector<int> để giữ nó khỏi việc khởi tạo nó trong tất cả khác (1000?) Tệp sử dụng vectơ.


200
2017-08-13 13:49



Ugh. Câu trả lời hay, nhưng không có giải pháp thực sự sạch sẽ. Liệt kê ra tất cả các loại có thể cho một mẫu có vẻ không giống với những gì một khuôn mẫu được cho là. - Jiminion
Điều này có thể tốt trong nhiều trường hợp nhưng thường phá vỡ mục đích của khuôn mẫu có nghĩa là để cho phép bạn sử dụng lớp với bất kỳ type mà không liệt kê chúng một cách thủ công. - Tomáš Zato
vector không phải là một ví dụ tốt vì một vùng chứa vốn đã nhắm mục tiêu các loại "tất cả". Nhưng nó xảy ra rất thường xuyên mà bạn tạo mẫu chỉ có nghĩa là cho một tập hợp các loại cụ thể, ví dụ các loại số: int8_t, int16_t, int32_t, uint8_t, uint16_t, v.v. Trong trường hợp này, vẫn có ý nghĩa khi sử dụng mẫu , nhưng rõ ràng instantiating chúng cho toàn bộ các loại cũng có thể và, theo ý kiến ​​của tôi, khuyến khích. - UncleZeiv
Được sử dụng sau khi mẫu đã được xác định, "và tất cả các hàm thành viên đã được xác định". Cảm ơn ! - Vitt Volt
Tôi muốn biết, có thể thực hiện các cảnh báo rõ ràng từ một nơi nào đó khác với tiêu đề của lớp hoặc tệp nguồn không? Ví dụ, làm chúng trong main.cpp? - gromit190


Đó là do yêu cầu cho việc biên dịch riêng biệt và bởi vì các khuôn mẫu là đa hình theo kiểu tức thời.

Cho phép nhận được một chút gần gũi hơn với bê tông cho một lời giải thích. Giả sử tôi có các tệp sau:

  • foo.h
    • khai báo giao diện của class MyClass<T>
  • foo.cpp
    • xác định việc thực hiện class MyClass<T>
  • bar.cpp
    • sử dụng MyClass<int>

Trình biên dịch riêng biệt có nghĩa là tôi có thể biên dịch foo.cpp độc lập từ bar.cpp. Trình biên dịch thực hiện tất cả các công việc khó khăn của việc phân tích, tối ưu hóa và tạo mã trên mỗi đơn vị biên dịch hoàn toàn độc lập; chúng tôi không cần phân tích toàn bộ chương trình. Đó chỉ là trình liên kết cần xử lý toàn bộ chương trình cùng một lúc và công việc của người liên kết là dễ dàng hơn nhiều.

bar.cpp thậm chí không cần phải tồn tại khi tôi biên dịch foo.cppnhưng tôi vẫn có thể liên kết foo.o Tôi đã có cùng với bar.o Tôi mới chỉ sản xuất mà không cần phải biên dịch lại foo.cpp. foo.cpp thậm chí có thể được biên dịch thành một thư viện động, được phân phối ở một nơi khác mà không cần foo.cppvà được liên kết với mã họ viết năm sau khi tôi viết foo.cpp.

"Đa hình theo phong cách tức thì" có nghĩa là mẫu MyClass<T> không thực sự là một lớp chung chung có thể được biên dịch thành mã có thể hoạt động với bất kỳ giá trị nào của T. Điều đó sẽ bổ sung thêm chi phí như boxing, cần truyền các con trỏ hàm tới các trình phân bổ và các nhà xây dựng, vv Mục đích của các mẫu C ++ là tránh phải viết gần như giống hệt nhau class MyClass_int, class MyClass_float, v.v. nhưng vẫn có thể kết thúc với mã được biên dịch hầu như là chúng ta đã có đã viết riêng từng phiên bản. Vì vậy, một mẫu là theo nghĩa đen một mẫu; một mẫu lớp là không phải một lớp, đó là một công thức để tạo một lớp mới cho mỗi T Chúng ta gặp phải. Một mẫu không thể được biên dịch thành mã, chỉ có kết quả của việc tạo mẫu có thể được biên dịch.

Vì vậy, khi foo.cpp được biên dịch, trình biên dịch không thể thấy bar.cpp biết rằng MyClass<int> là cần thiết. Nó có thể thấy mẫu MyClass<T>, nhưng nó không thể phát ra mã cho nó (đó là một khuôn mẫu, không phải là một lớp). Và khi bar.cpp được biên dịch, trình biên dịch có thể thấy rằng nó cần tạo MyClass<int>, nhưng không thể thấy mẫu MyClass<T> (chỉ giao diện của nó trong foo.h) vì vậy nó không thể tạo ra nó.

Nếu foo.cpp chính nó sử dụng MyClass<int>, sau đó mã cho sẽ được tạo trong khi biên dịch foo.cpp, khi nào bar.o được liên kết với foo.o chúng có thể được nối và sẽ hoạt động. Chúng ta có thể sử dụng thực tế đó để cho phép một tập hợp các mẫu instantite hữu hạn được thực hiện trong một tệp .cpp bằng cách viết một mẫu đơn. Nhưng không có cách nào cho bar.cpp để sử dụng mẫu làm mẫu và khởi tạo nó trên bất kỳ loại nào nó thích; nó chỉ có thể sử dụng các phiên bản trước đó của lớp templated mà tác giả của foo.cpp suy nghĩ để cung cấp.

Bạn có thể nghĩ rằng khi biên dịch một khuôn mẫu trình biên dịch nên "tạo tất cả các phiên bản", với các trình biên dịch không bao giờ được sử dụng để lọc ra trong quá trình liên kết. Bên cạnh chi phí khổng lồ và những khó khăn cực đoan như một cách tiếp cận sẽ phải đối mặt bởi vì "loại modifier" tính năng như con trỏ và mảng cho phép thậm chí chỉ là các loại được xây dựng trong để cung cấp cho một số lượng vô hạn các loại, những gì sẽ xảy ra khi tôi bây giờ mở rộng chương trình của tôi bằng cách thêm:

  • baz.cpp
    • tuyên bố và thực hiện class BazPrivatevà sử dụng MyClass<BazPrivate>

Không có cách nào có thể làm được điều này trừ khi chúng ta

  1. Phải biên dịch lại foo.cpp mỗi khi chúng ta thay đổi bất kỳ tệp nào khác trong chương trình, trong trường hợp nó được thêm vào một cuốn tiểu thuyết mới MyClass<T>
  2. Yêu cầu baz.cpp chứa (có thể thông qua tiêu đề bao gồm) mẫu đầy đủ của MyClass<T>, để trình biên dịch có thể tạo MyClass<BazPrivate> trong quá trình biên dịch baz.cpp.

Không ai thích (1), bởi vì toàn bộ chương trình phân tích các hệ thống biên dịch mãi mãi để biên dịch và vì nó không thể phân phối các thư viện được biên dịch mà không có mã nguồn. Vì vậy, chúng tôi có (2) thay vào đó.


173
2018-05-11 03:54



báo giá nhấn mạnh một mẫu theo nghĩa đen là một mẫu; một lớp mẫu không phải là một lớp, đó là một công thức để tạo một lớp mới cho mỗi T chúng ta gặp phải - v.oddou
Tôi muốn biết, có thể thực hiện các cảnh báo rõ ràng từ một nơi nào đó khác với tiêu đề của lớp hoặc tệp nguồn không? Ví dụ, làm chúng trong main.cpp? - gromit190
@Birger Bạn có thể làm điều đó từ bất kỳ tệp nào có quyền truy cập vào việc triển khai mẫu đầy đủ (hoặc vì nó nằm trong cùng một tệp hoặc thông qua tiêu đề bao gồm). - Ben
Câu trả lời này như thế nào? Nó cung cấp không có giải pháp nhưng chỉ có tính hùng biện. - ajeh
@ajeh Nó không phải là hùng biện. Câu hỏi đặt ra là "tại sao bạn phải thực hiện các mẫu trong một tiêu đề?", Vì vậy tôi đã giải thích các lựa chọn kỹ thuật ngôn ngữ C ++ làm cho dẫn đến yêu cầu này. Trước khi tôi viết câu trả lời của mình, những người khác đã cung cấp cách giải quyết không phải là giải pháp đầy đủ, bởi vì có không thể là một giải pháp đầy đủ. Tôi cảm thấy những câu trả lời đó sẽ được bổ sung bằng một cuộc thảo luận đầy đủ về góc "tại sao" của câu hỏi. - Ben


Mẫu cần phải khởi tạo bởi trình biên dịch trước khi biên dịch chúng thành mã đối tượng. Sự khởi tạo này chỉ có thể đạt được nếu các đối số mẫu được biết. Bây giờ hãy tưởng tượng một kịch bản trong đó một hàm mẫu được khai báo trong a.h, được định nghĩa trong a.cpp và được sử dụng trong b.cpp. Khi nào a.cpp được biên dịch, không nhất thiết phải biết rằng biên soạn sắp tới b.cpp sẽ yêu cầu một thể hiện của mẫu, hãy để một mình trường hợp cụ thể nào có thể. Đối với nhiều tệp tiêu đề và nguồn hơn, tình huống có thể nhanh chóng trở nên phức tạp hơn.

Người ta có thể tranh luận rằng các trình biên dịch có thể được thực hiện thông minh hơn để "nhìn về phía trước" cho tất cả các ứng dụng của mẫu, nhưng tôi chắc chắn rằng sẽ không khó để tạo ra các kịch bản phức tạp hoặc phức tạp. AFAIK, trình biên dịch không làm như vậy nhìn aheads. Như Anton đã chỉ ra, một số trình biên dịch hỗ trợ khai báo xuất khẩu rõ ràng của các mẫu instantiations, nhưng không phải tất cả các trình biên dịch đều hỗ trợ nó (chưa?).


64
2018-01-30 10:23



"xuất khẩu" là tiêu chuẩn, nhưng nó chỉ khó thực hiện vì vậy hầu hết các đội biên dịch chưa thực hiện. - vava
xuất khẩu không loại bỏ nhu cầu tiết lộ nguồn, cũng như không làm giảm các phụ thuộc biên dịch, trong khi nó đòi hỏi một nỗ lực lớn từ các nhà xây dựng trình biên dịch. Vì vậy, Herb Sutter tự hỏi các nhà xây dựng trình biên dịch để 'quên đi' xuất khẩu. Khi đầu tư thời gian cần thiết sẽ chi tiêu tốt hơn ở nơi khác ... - Pieter
Vì vậy, tôi không nghĩ rằng xuất khẩu không được thực hiện 'chưa'. Nó có lẽ sẽ không bao giờ được thực hiện bởi bất cứ ai khác hơn EDG sau khi những người khác thấy nó mất bao lâu, và làm thế nào ít thu được - Pieter
Nếu bạn quan tâm, bài báo được gọi là "Tại sao chúng tôi không thể đủ khả năng xuất", nó được liệt kê trên blog của anh ấy (gotw.ca/publications) nhưng không có pdf ở đó (một google nhanh chóng nên bật nó lên mặc dù) - Pieter
Ok, cảm ơn ví dụ và giải thích tốt. Đây là câu hỏi của tôi mặc dù: tại sao trình biên dịch không thể tìm ra nơi mẫu được gọi, và biên dịch những tập tin đầu tiên trước khi biên dịch tập tin định nghĩa? Tôi có thể tưởng tượng nó có thể được thực hiện trong một trường hợp đơn giản ... Câu trả lời là phụ thuộc lẫn nhau sẽ làm rối trật tự khá nhanh? - Vlad


Trên thực tế, các phiên bản của tiêu chuẩn C ++ trước C ++ 11 đã xác định từ khóa 'xuất', sẽ làm cho nó có thể chỉ đơn giản là tuyên bố các mẫu trong một tập tin tiêu đề và thực hiện chúng ở nơi khác.

Thật không may, không có trình biên dịch phổ biến nào được triển khai từ khóa này. Người duy nhất tôi biết là frontend được viết bởi Edison Design Group, được sử dụng bởi trình biên dịch Comeau C ++. Tất cả những người khác khẳng định bạn viết các mẫu trong các tệp tiêu đề, cần định nghĩa của mã cho việc khởi tạo thích hợp (như những người khác đã chỉ ra).

Kết quả là, ủy ban tiêu chuẩn ISO C ++ đã quyết định xóa export tính năng của các mẫu bắt đầu bằng C ++ 11.


47
2018-01-30 13:38



Trong một mẫu xuất kết quả đã được gỡ bỏ từ C ++ 11. - johannes
@johannes: Tôi không hiểu điều đó, cảm ơn. Thực tế, bạn không thể sử dụng export dù sao kể từ đó sẽ buộc bạn với trình biên dịch Comeau. Đó là một "tính năng chết"; chỉ là một cái tôi rất thích nhìn thấy được triển khai ở khắp mọi nơi. - DevSolar
... và vài năm sau, tôi cuối cùng hiểu những gì export thực sự sẽ có được chúng tôi, và những gì không ... và bây giờ tôi hết lòng đồng ý với những người EDG: Nó sẽ không mang lại cho chúng tôi những gì hầu hết mọi người (bản thân tôi trong '11 bao gồm) suy nghĩ nó sẽ, và tiêu chuẩn C ++ là tốt hơn mà không có nó. - DevSolar
@DevSolar: bài viết này là chính trị, lặp đi lặp lại và viết kém. đó không phải là văn xuôi tiêu chuẩn thông thường ở đó. Không lâu và nhàm chán, nói về cơ bản gấp 3 lần những thứ giống nhau trên hàng chục trang. Nhưng bây giờ tôi được thông báo rằng xuất khẩu không xuất khẩu. Đó là một intel tốt! - v.oddou
@ v.oddou: Nhà phát triển giỏi và nhà văn kỹ thuật giỏi là hai kỹ năng riêng biệt. Một số có thể làm cả hai, nhiều người không thể. ;-) - DevSolar


Mặc dù tiêu chuẩn C ++ không có yêu cầu như vậy, một số trình biên dịch yêu cầu tất cả các mẫu chức năng và lớp cần phải được cung cấp trong mọi đơn vị dịch mà chúng được sử dụng. Trong thực tế, đối với những trình biên dịch đó, các phần tử của các hàm mẫu phải được tạo sẵn trong một tệp tiêu đề. Để lặp lại: điều đó có nghĩa là các trình biên dịch đó sẽ không cho phép chúng được định nghĩa trong các tệp không phải tiêu đề như tệp .cpp

Đây là một xuất khẩu từ khóa được cho là để giảm thiểu vấn đề này, nhưng nó gần như không thể di chuyển được.


31
2018-01-30 10:15



Tại sao tôi không thể triển khai chúng trong tệp .cpp với từ khóa "inline"? - MainID
Bạn có thể, và bạn không cần phải đặt "inline" ngay cả. Nhưng bạn có thể sử dụng chúng chỉ trong tệp cpp đó và không có nơi nào khác. - vava
Đây gần như là nhất chính xác trả lời, ngoại trừ "có nghĩa là những trình biên dịch sẽ không cho phép chúng được định nghĩa trong các tệp không phải tiêu đề như tệp .cpp" là giả mạo sai. - Lightness Races in Orbit


Các mẫu phải được sử dụng trong các tiêu đề bởi vì trình biên dịch cần phải khởi tạo các phiên bản khác nhau của mã, tùy thuộc vào các tham số đã cho / được suy ra cho các tham số mẫu. Hãy nhớ rằng một mẫu không đại diện cho mã trực tiếp, mà là một mẫu cho một số phiên bản của mã đó. Khi bạn biên dịch một hàm không phải mẫu trong một .cpptập tin, bạn đang biên dịch một hàm / lớp cụ thể. Đây không phải là trường hợp cho các mẫu, có thể được khởi tạo với các kiểu khác nhau, cụ thể là, mã bê tông phải được phát ra khi thay thế các tham số mẫu bằng các kiểu cụ thể.

Có một tính năng với export từ khóa được sử dụng để biên dịch riêng biệt. Các export tính năng không được chấp nhận trong C++11 và, AFAIK, chỉ có một trình biên dịch thực hiện nó. Bạn không nên sử dụng export. Không thể biên dịch riêng biệt trong C++ hoặc là C++11 nhưng có lẽ trong C++17, nếu các khái niệm tạo ra nó, chúng ta có thể có một số cách để biên dịch riêng biệt.

Để có thể biên dịch riêng biệt, có thể thực hiện kiểm tra thân máy mẫu riêng biệt. Dường như một giải pháp là có thể với các khái niệm. Hãy xem này giấy mới được trình bày tại tiêu chuẩn commitee họp. Tôi nghĩ đây không phải là yêu cầu duy nhất, vì bạn vẫn cần phải khởi tạo mã cho mã mẫu trong mã người dùng.

Các vấn đề biên dịch riêng biệt cho các mẫu tôi đoán nó cũng là một vấn đề phát sinh với việc di chuyển đến các mô-đun, hiện đang được làm việc.


26
2018-05-12 16:42





Nó có nghĩa là cách di động nhất để xác định việc triển khai phương thức của các lớp mẫu là xác định chúng bên trong định nghĩa lớp mẫu.

template < typename ... >
class MyClass
{

    int myMethod()
    {
       // Not just declaration. Add method implementation here
    }
};

13
2018-01-30 10:53





Mặc dù có rất nhiều giải thích tốt ở trên, tôi thiếu một cách thực tế để tách các mẫu thành tiêu đề và nội dung.
Mối quan tâm chính của tôi là tránh biên dịch lại tất cả người dùng mẫu, khi tôi thay đổi định nghĩa của nó.
Việc có tất cả các mẫu instantiations trong phần thân mẫu không phải là một giải pháp khả thi đối với tôi, vì tác giả mẫu có thể không biết tất cả nếu việc sử dụng nó và người dùng mẫu có thể không có quyền sửa đổi nó.
Tôi đã sử dụng phương pháp tiếp cận sau, hoạt động cũng cho các trình biên dịch cũ hơn (gcc 4.3.4, aCC A.03.13).

Đối với mỗi mẫu sử dụng, có một typedef trong tệp tiêu đề của chính nó (được tạo ra từ mô hình UML). Cơ thể của nó chứa các instantiation (mà kết thúc trong một thư viện được liên kết ở cuối).
Mỗi người dùng của mẫu bao gồm tệp tiêu đề đó và sử dụng typedef.

Một ví dụ sơ đồ:

MyTemplate.h:

#ifndef MyTemplate_h
#define MyTemplate_h 1

template <class T>
class MyTemplate
{
public:
  MyTemplate(const T& rt);
  void dump();
  T t;
};

#endif

MyTemplate.cpp:

#include "MyTemplate.h"
#include <iostream>

template <class T>
MyTemplate<T>::MyTemplate(const T& rt)
: t(rt)
{
}

template <class T>
void MyTemplate<T>::dump()
{
  cerr << t << endl;
}

MyInstantiatedTemplate.h:

#ifndef MyInstantiatedTemplate_h
#define MyInstantiatedTemplate_h 1
#include "MyTemplate.h"

typedef MyTemplate< int > MyInstantiatedTemplate;

#endif

MyInstantiatedTemplate.cpp:

#include "MyTemplate.cpp"

template class MyTemplate< int >;

main.cpp:

#include "MyInstantiatedTemplate.h"

int main()
{
  MyInstantiatedTemplate m(100);
  m.dump();
  return 0;
}

Bằng cách này, chỉ các bản mẫu sẽ cần phải được biên dịch lại, không phải tất cả người dùng mẫu (và các phụ thuộc).


9
2018-05-12 14:02





Đó là chính xác bởi vì trình biên dịch phải biết loại đó là gì để phân bổ. Vì vậy, các lớp mẫu, hàm, enums, v.v. phải được thực hiện tốt trong tệp tiêu đề nếu nó được công khai hoặc một phần của thư viện (tĩnh hoặc động) vì tệp tiêu đề KHÔNG được biên dịch không giống như tệp c / cpp là. Nếu trình biên dịch không biết loại không thể biên dịch nó. Trong. Net nó có thể bởi vì tất cả các đối tượng xuất phát từ lớp Object. Đây không phải là .Net.


6
2017-09-17 03:40



"các tệp tiêu đề KHÔNG được biên dịch" - đó là một cách thực sự kỳ lạ khi mô tả nó. Tệp tiêu đề có thể là một phần của đơn vị dịch, giống như tệp "c / cpp". - Flexo♦
Trong thực tế, nó gần như trái ngược với sự thật, đó là các tập tin tiêu đề được biên dịch rất thường xuyên nhiều lần, trong khi một tập tin nguồn thường được biên dịch một lần. - xaxxon