Sử dụng từ khóa nội dòng với các mẫu có ý nghĩa gì không?


119

Vì các mẫu được định nghĩa trong tiêu đề và trình biên dịch có thể xác định xem nội tuyến một hàm có lợi hay không, nó có ý nghĩa gì không? Tôi nghe nói rằng các trình biên dịch hiện đại biết rõ hơn khi nào cần nội tuyến một hàm và đang bỏ qua inlinegợi ý.


chỉnh sửa: Tôi muốn chấp nhận cả hai câu trả lời, nhưng điều này là không thể. Để kết thúc vấn đề, tôi chấp nhận câu trả lời của phresnel , vì nó nhận được hầu hết các phiếu bầu và anh ấy chính thức đúng, nhưng như tôi đã đề cập trong phần bình luận, tôi coi câu trả lời của PuppyThành phần 10 cũng là câu trả lời đúng, theo quan điểm khác .

Vấn đề là ở ngữ nghĩa C ++, không chặt chẽ trong trường hợp inlinetừ khóa và nội dòng. phresnel nói "viết nội tuyến nếu bạn có ý đó", nhưng ý nghĩa thực sự của inlinenó là gì thì không rõ ràng vì nó phát triển từ ý nghĩa ban đầu thành chỉ thị "dừng các trình biên dịch nói xấu về vi phạm ODR" như Puppy nói.

Câu trả lời:


96

Nó không phải là không liên quan. Và không, không phải mọi mẫu hàm đều là inlinetheo mặc định. Tiêu chuẩn thậm chí còn rõ ràng về nó trong Chuyên môn hóa rõ ràng ([temp.expl.spec])

Có những thứ sau:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (lấy từ Chuyên môn rõ ràng):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Biên dịch cái này, et thì đấy:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Không nêu rõ inlinekhi nào thực hiện thuyết minh rõ ràng cũng có thể dẫn đến các vấn đề.

Vì vậy, tóm lại : Đối với các mẫu hàm không chuyên biệt hoàn toàn, tức là những mẫu mang ít nhất một loại không xác định, bạn có thể bỏ qua inlinevà không nhận được lỗi, nhưng chúng vẫn không inline. Đối với các chuyên ngành đầy đủ, tức là những chuyên ngành chỉ sử dụng các loại đã biết, bạn không thể bỏ qua.

Quy tắc ngón tay cái được đề xuất : Viết inlinenếu bạn có ý đó và chỉ cần nhất quán. Nó khiến bạn ít suy nghĩ về việc có nên hay không chỉ vì bạn có thể. (Quy tắc ngón tay cái này tuân theo Mẫu C ++ của Vandevoorde / Josuttis : Hướng dẫn hoàn chỉnh ).


2
Người ta có thể đã viết, đúng. Nhưng điều đó không có nghĩa là nội tuyến, ngay cả khi nó xuất hiện như vậy. Vandevoorde và Josuttis cũng nêu chính xác điều đó trong Mẫu C ++: Hướng dẫn đầy đủ
Sebastian Mach

43
Chuyên môn rõ ràng không phải là một khuôn mẫu.
Puppy

2
@DeadMG: Tuy nhiên, một chức năng bình thường được ưu tiên hơn một chuyên môn hóa đầy đủ khi tra cứu, vì vậy nếu chúng không phải là mẫu hoặc không phải là mẫu, thì chúng là gì?
Sebastian Mach

13
Câu trả lời này không chính xác. Một chuyên môn hóa rõ ràng của một mẫu là một chức năng, không phải một khuôn mẫu. Chức năng đó không trở thành inlinechỉ vì mẫu được chuyên biệt hóa được đánh dấu bằng inline. Vì vậy, inlinetrên mẫu là hoàn toàn không liên quan. Cho dù chức năng đó có nên inlinehay không không liên quan gì đến việc nó được tạo ra thông qua một chuyên môn hóa mẫu (và có những câu trả lời tốt hơn là địa chỉ này khi sử dụng inline). Câu trả lời của @Puppy dưới đây là đúng, câu này thì không. Việc thêm inlinevào một mẫu là không liên quan và clang-tidysẽ thực sự loại bỏ nó.
gnzlbg

6
Ngoài ra, ví dụ chỉ trình bày các vấn đề ODR cho các chức năng bình thường (hành vi không liên quan gì đến các mẫu). Để cố gắng chứng tỏ rằng inlinekhông thể không thích hợp, ví dụ nên bao gồm các trường hợp chuyên một cách rõ ràng template<> void f<>(int) {} mà không cần các inlinetừ khóa. Nhưng ngay cả sau đó thay đổi thông số inlinetrên mẫu cũng không tạo ra bất kỳ sự khác biệt nào, bởi vì bạn có đánh dấu mẫu inlinehay không là không liên quan.
gnzlbg

34

Nó không liên quan. Tất cả các mẫu đều đã có inline- chưa kể đến năm 2012, việc sử dụng inlinetừ khóa duy nhất là ngừng các trình biên dịch phàn nàn về các vi phạm ODR. Bạn hoàn toàn chính xác - trình biên dịch thế hệ hiện tại của bạn sẽ tự biết những gì cần nội tuyến và có thể làm như vậy ngay cả giữa các đơn vị dịch.


11
Tiêu chuẩn không nêu rằng tất cả các mẫu đều là nội tuyến.
Sebastian Mach

16
@phresnel: Nhưng các mẫu có cùng ngữ nghĩa với các inlinehàm-đánh dấu (nghĩa là, nhiều định nghĩa tương đương có thể được chuyển đến trình liên kết, trình liên kết sẽ chọn một). Đó, không phải là nội tuyến, là chức năng thực sự của inlinetừ khóa.
Ben Voigt

2
@BenVoigt: Tôi biết về ý nghĩa của ODR inline. Có thể xem qua câu trả lời của tôi bên dưới (hoặc ở trên, tùy thuộc vào cách sắp xếp đã chọn). Đối với các mẫu không chuyên, bạn tất nhiên đúng, nhưng về mặt hình thức thì không giống nhau.
Sebastian Mach

3
@DeadMG: Không có yêu cầu nào trong C ++ rằng mẫu hàm phải được triển khai trong tệp tiêu đề; nó có thể được thực hiện ở bất cứ đâu. Để phản ánh điều này, tôi có xu hướng khuyên bạn nên gắn thẻ inlinenhững gì được cho là nội tuyến. Nó thường không có gì khác biệt, nhưng trong tiêu chuẩn, chúng không giống nhau và không phải tất cả đều nội tuyến. Tôi chấp nhận lập trường của bạn về nó nói rằng "Nó không liên quan", nhưng theo tiêu chuẩn, không phải tất cả các mẫu đều nội dòng, chỉ dành cho bạn là người dùng C ++ - chúng xuất hiện như thể.
Sebastian Mach

7
Nhận xét của bạn về câu trả lời được chấp nhận rằng chuyên môn hóa rõ ràng không phải là một khuôn mẫu (tất nhiên là điều hiển nhiên sau khi được thông báo như vậy ....) có lẽ là điều hữu ích nhất trên trang này. Bạn có phiền thêm nó vào câu trả lời của bạn không?
Kyle Strand

6

Như bạn đã đề xuất, inlinelà một gợi ý cho trình biên dịch và không có gì hơn. Nó có thể chọn bỏ qua nó hoặc thực sự là các hàm nội tuyến không được đánh dấu nội tuyến.

Sử dụng inlinevới các mẫu được sử dụng là một cách (kém) để giải quyết vấn đề rằng mỗi đơn vị biên dịch sẽ tạo một đối tượng riêng biệt cho cùng một lớp mẫu, sau đó sẽ gây ra vấn đề trùng lặp tại thời điểm liên kết. Bằng cách sử dụng inline(tôi nghĩ) tên mangling hoạt động khác nhau, làm cho xung đột tên quanh thời gian liên kết nhưng với chi phí của mã quá cồng kềnh.  

Marshall Cline giải thích nó ở đây tốt hơn tôi có thể.


@Xeo: Điều đó đã từng không xảy ra. Kiểm tra tại đây: gcc.gnu.org/onlineocs/gcc-4.0.4/gcc/… Tôi cho rằng điều đó đã thay đổi gần đây hơn, đó là lý do tại sao tôi đang nói ở thì quá khứ.
Thành phần 10

2
@Xeo: Bạn có thể chỉ cho tôi phần của Tiêu chuẩn nói rằng các mẫu hàm luôn nội dòng không? Bởi vì, chúng không phải vậy.
Sebastian Mach

@phresnel: Thật thú vị, tôi có thể thề rằng tôi đã đọc nó theo tiêu chuẩn. Có lẽ tôi đã trộn nó với thực tế là các mẫu hàm được miễn khỏi ODR ( §14.5.5.1 p7 & p8). Tệ của tôi, tôi đã xóa bình luận sai.
Xeo

@Component 10 Tại sao bạn nghĩ rằng đó là cách người nghèo nhận được vấn đề vòng biên soạn
Kapil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.