2009-11-19 18 views
5

phép nói rằng bạn có chức năng template đơn giản (không lớp thành viên vì lợi ích của sự đơn giản) với kiểu chuyên môn cụ thể trong file .h cùng ...Trình biên dịch có được phép bỏ qua nội tuyến trong trường hợp chuyên môn hóa mẫu không?

template <class TYPE> 
void some_function(TYPE& val) 
{ 
    // some generic implementation 
} 

template <> 
inline void some_function<int>(int& val) 
{ 
    // some int specific implementation 
} 

Trừ khi bạn rõ ràng hướng dẫn bạn trình biên dịch để inline sự chuyên môn hóa (inline từ khóa) bạn sẽ nhận được lỗi liên kết nếu tệp .h được bao gồm nhiều lần (ít nhất là tôi làm trong Visual C++ 2008).
Chúng ta đều biết rằng inline chỉ là một gợi ý cho trình biên dịch, mà nó có thể bỏ qua. Trong trường hợp cụ thể này trình biên dịch được phép bỏ qua gợi ý này và để cho trình liên kết thất bại?

+0

Đây là một trong những góc tối C++ khác. –

+2

Đọc phần này: http://stackoverflow.com/questions/1759300/c-when-should-i-write-the-keyword-inline-for-a-function-method/1759575#1759575 –

Trả lời

5

Bạn hiểu lầm ý nghĩa của khả năng "bỏ qua nội tuyến" thường được đề cập.

Không trình biên dịch nào được phép bỏ qua thông số inline được sử dụng trong khai báo chức năng và hậu quả mà trình chỉ định này có liên quan đến Quy tắc một định nghĩa (ODR).

Khi ai đó nói rằng trình biên dịch được phép "bỏ qua nội tuyến", điều đó chỉ có nghĩa là trình biên dịch không bắt buộc phải thực hiện các cuộc gọi cho hàm đang được đề cập. Để "bỏ qua nội tuyến" có nghĩa là tạo một cuộc gọi hàm bình thường (không được nội tuyến) đến một hàm nội tuyến.

Trong mọi trường hợp, ngay cả khi trình biên dịch quyết định luôn tạo các cuộc gọi thông thường đến hàm nội tuyến (tức là luôn "bỏ qua nội tuyến"), thì vẫn cần phải xử lý hàm như nội tuyến cho mục đích ODR. Làm thế nào trình biên dịch sẽ làm điều đó là vấn đề của trình biên dịch. Bạn không phải lo lắng về nó.

Trong ví dụ ban đầu của bạn, bạn không nên nhận bất kỳ lỗi nào của trình liên kết.

+0

Cảm ơn Andrey, đây là câu hỏi của tôi. – BostonLogan

7

Nếu bạn không sử dụng inline, thì chức năng tương tự sẽ được biên dịch với extern liên kết thành nhiều tệp .obj, làm cho trình liên kết phát ra lỗi biểu tượng trùng lặp.

Điều này độc lập với việc trình biên dịch thực sự biên dịch nội dòng của bạn, vì nó có thể xử lý nó giống như hàm static và thực hiện từng cài đặt riêng cho từng đơn vị biên dịch. Tuy nhiên, bạn không thể sử dụng static cho mục đích này vì nó có nghĩa là một cái gì đó khác về chức năng thành viên, do đó, inline là lựa chọn duy nhất của bạn.

+0

Cảm ơn Greg. Tôi có đúng để giả định rằng nội tuyến là từ khóa mục đích kép không? Và trong trường hợp chuyên môn hóa mẫu, liên kết bên ngoài bị chặn trong khi chức năng vẫn có thể là nội tuyến hay không? Hàm – BostonLogan

+0

'inline' vẫn có liên kết bên ngoài (3.5/3). ODR có một trường hợp đặc biệt để cho phép một định nghĩa của chúng trong mỗi TU, tuy nhiên. –

+0

@BostonLogan: nó sẽ thực sự hữu ích nếu mọi người ngừng sử dụng các cụm từ như "nội tuyến". ;-) Nếu một hàm có từ khóa nội tuyến (hoặc ngầm hoàn toàn giống như các mẫu được tạo ra ngầm và các hàm thành viên được định nghĩa trong một định nghĩa lớp), thì trong thuật ngữ C++ nó là "inline". Cho dù trình biên dịch chỉ ra một cuộc gọi cụ thể đến một hàm không phải là thuộc tính của hàm, đầu tiên là do trình biên dịch (có thể lấy trạng thái nội tuyến dưới dạng gợi ý), và thứ hai vì nó có thể đúng với một số cuộc gọi chứ không phải các cuộc gọi khác. –

0

Tôi tin rằng bạn có thể tuyên bố rõ ràng phương thức là extern và sau đó đưa chuyên môn vào tệp .cpp. Tôi đã thử một cái gì đó tương tự trong một cuộc sống quá khứ với GCC, nhưng tôi không nhớ lại các chi tiết chính xác về cách nó hoạt động. MSDN Magazine has an article on this có thể hữu ích.

0

Điều bạn đang thực sự thấy là Quy tắc một định nghĩa (ODR) có trường hợp đặc biệt cho các hàm nội tuyến, trong đó mỗi TU có thể có định nghĩa. Nếu chức năng, chẳng hạn như chuyên môn int rõ ràng của bạn, không phải là nội tuyến, sau đó bạn sẽ nhận được nhiều lỗi định nghĩa tại thời gian liên kết. Các hàm nội tuyến như vậy vẫn có liên kết bên ngoài. Mẫu chức năng là mẫu và do đó tuân theo các quy tắc khác nhau. Các phiên âm/chuyên môn của mẫu chức năng là chức năng.

Sử dụng nội tuyến, như đối với bất kỳ chức năng nào, chỉ là gợi ý, nhưng bạn có thể muốn áp dụng nó nếu hàm này ngắn (như đối với bất kỳ hàm nào) hoặc nếu bạn chỉ muốn giữ nó trong tiêu đề. Dưới đây là một ví dụ mà không inline:

header file:

template<class TYPE> 
void some_function(TYPE& val) { 
    // some generic implementation 
} 

template<> 
void some_function<int>(int& val); 

thực hiện (cpp) file:

template<> 
void some_function<int>(int& val) { 
    // some int specific implementation 
} 
1

này được xác định bởi tiêu chuẩn và trình biên dịch là hoàn toàn phù hợp trong lĩnh vực này, từ vẻ ngoài của nó. Mối liên kết là tất cả những gì bạn đang có. Implicit mẫu instantiations có 'đặc biệt' liên kết, như chức năng nội tuyến làm. Ngoài ra còn có tĩnh (từ khóa), đã được phản đối ủng hộ không gian tên vô danh:

namespace { 
    …declarations… 
} 

Vì vậy, có, chuyên môn hóa này (trong ví dụ của bạn) có mối liên hệ tương tự như:

void some_other_function(int& val) { 
    // some int specific implementation 
} 

Trong thực tế , trình biên dịch có thể lầm bầm về việc nhấn mạnh chuyên môn hóa, trong ví dụ của bạn, nói rằng chúng không khớp. Vì vậy, nó thực sự là một thực hành tốt nhất để gắn nhãn cho cả hai nội tuyến (hoặc nếu không).

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