ý nghĩa nội tuyến trong giao diện mô-đun


24

Hãy xem xét tệp tiêu đề:

class T
{
private:
  int const ID;

public:
  explicit T(int const ID_) noexcept : ID(ID_) {}

  int GetID() const noexcept { return ID; }
};

Hay cách khác:

class T
{
private:
  int const ID;

public:
  explicit T(int const ID_) noexcept;

  int GetID() const noexcept;
};

inline T::T(int const ID_) noexcept : ID(ID_) {}

inline int T::GetID() const noexcept { return ID; }

Trong một thế giới tiền mô-đun, các tiêu đề này có thể được bao gồm bằng văn bản trong nhiều TU mà không vi phạm ODR. Hơn nữa, vì các hàm thành viên có liên quan tương đối nhỏ, trình biên dịch có thể sẽ "nội tuyến" (tránh các lệnh gọi hàm khi sử dụng) các hàm đó, hoặc thậm chí tối ưu hóa Thoàn toàn một số trường hợp .

Trong một báo cáo gần đây về cuộc họp nơi C ++ 20 đã kết thúc, tôi có thể đọc tuyên bố sau:

Chúng tôi đã làm rõ ý nghĩa của các inlinegiao diện mô-đun: mục đích là các phần tử của các hàm không được khai báo rõ ràng inlinekhông phải là một phần của ABI của một mô-đun, ngay cả khi các thân hàm đó xuất hiện trong giao diện mô-đun. Để cung cấp cho các tác giả mô-đun quyền kiểm soát nhiều hơn đối với ABI của họ, các hàm thành viên được xác định trong các thân lớp trong các giao diện mô-đun không còn hoàn toàn inline.

Tôi không chắc là tôi không nhầm. Điều đó có nghĩa là, trong một thế giới mô-đun, để trình biên dịch có thể tối ưu hóa các lệnh gọi hàm, chúng ta phải chú thích chúng inlinengay cả khi chúng được định nghĩa trong lớp?

Nếu vậy, giao diện mô-đun sau có tương đương với các tiêu đề ở trên không?

export module M;

export
class T
{
private:
  int const ID;

public:
  inline explicit T(int const ID_) noexcept : ID(ID_) {}

  inline int GetID() const noexcept { return ID; }
};

Mặc dù tôi vẫn không có trình biên dịch với các mô-đun hỗ trợ, tôi muốn bắt đầu sử dụng inlinenhư vậy khi thích hợp, để giảm thiểu tái cấu trúc trong tương lai.

Câu trả lời:


11

Điều đó có nghĩa là, trong một thế giới mô-đun, để trình biên dịch có thể tối ưu hóa các lệnh gọi hàm, chúng ta phải chú thích chúng inlinengay cả khi chúng được định nghĩa trong lớp?

Đến một mức độ nào.

Nội tuyến là tối ưu hóa "như thể" và nội tuyến có thể xảy ra ngay cả giữa các đơn vị dịch nếu trình biên dịch đủ thông minh.

Điều đó đang được nói, nội tuyến là dễ nhất khi làm việc trong một đơn vị dịch thuật. Do đó, để thúc đẩy nội tuyến dễ dàng, inlinehàm -declared phải có định nghĩa được cung cấp trong bất kỳ đơn vị dịch thuật nào được sử dụng. Điều này không có nghĩa là trình biên dịch chắc chắn sẽ nội tuyến nó (hoặc chắc chắn không nội tuyến bất kỳ inlinechức năng không đủ tiêu chuẩn nào), nhưng nó làm cho mọi thứ dễ dàng hơn nhiều trong quá trình nội tuyến, vì việc nội tuyến đang diễn ra trong TU thay vì giữa chúng.

Các định nghĩa thành viên lớp được định nghĩa trong một lớp, trong thế giới tiền mô-đun, được khai báo inlinengầm. Tại sao? Bởi vì định nghĩa là trong lớp. Trong một thế giới tiền mô-đun, các định nghĩa lớp được chia sẻ giữa các TU được chia sẻ bằng cách đưa vào văn bản. Do đó, các thành viên được xác định trong một lớp sẽ được xác định trong tiêu đề được chia sẻ giữa các TU đó. Vì vậy, nếu nhiều TU sử dụng cùng một lớp, thì nhiều TU đó sẽ làm như vậy bằng cách bao gồm định nghĩa lớp và định nghĩa của các thành viên được khai báo trong tiêu đề.

Đó là, dù sao bạn cũng bao gồm định nghĩa , vậy tại sao không làm cho nó inline?

Tất nhiên, điều này có nghĩa là định nghĩa của hàm bây giờ là một phần của văn bản của lớp. Nếu bạn thay đổi định nghĩa của một thành viên được khai báo trong một tiêu đề, điều này buộc phải biên dịch lại mọi tệp bao gồm tiêu đề đó, theo cách đệ quy. Ngay cả khi giao diện của lớp không thay đổi, bạn vẫn cần thực hiện biên dịch lại. Vì vậy, làm cho các chức năng như vậy hoàn toàn inlinekhông thay đổi điều này, vì vậy bạn cũng có thể làm điều đó.

Để tránh điều này trong thế giới tiền mô-đun, bạn chỉ cần xác định thành viên trong tệp C ++, sẽ không được bao gồm trong các tệp khác. Bạn mất nội tuyến dễ dàng, nhưng bạn có được thời gian biên dịch.

Nhưng đây là điều: đây là một tạo tác của việc sử dụng văn bản bao gồm như một phương tiện để đưa một lớp đến nhiều nơi.

Trong một thế giới mô-đun, có lẽ bạn sẽ muốn xác định từng hàm thành viên trong chính lớp đó, như chúng ta thấy trong các ngôn ngữ khác như Java, C #, Python và tương tự. Điều này giữ cho địa phương mã hợp lý và nó ngăn không phải nhập lại chữ ký hàm tương tự, do đó phục vụ nhu cầu của DRY.

Nhưng nếu tất cả các thành viên được định nghĩa trong định nghĩa lớp, thì theo các quy tắc cũ, tất cả các thành viên đó sẽ là inline. Và để một mô-đun cho phép một chức năng trở thành inline, tạo tác mô-đun nhị phân sẽ phải bao gồm định nghĩa của các chức năng đó. Điều đó có nghĩa là bất cứ khi nào bạn thay đổi ngay cả một dòng mã theo định nghĩa hàm như vậy, mô-đun sẽ phải được xây dựng, cùng với mọi mô-đun tùy thuộc vào nó, theo cách đệ quy.

Việc loại bỏ inlinecác mô-đun ngầm định mang đến cho người dùng những quyền hạn giống như họ có trong những ngày đưa vào văn bản, mà không phải chuyển định nghĩa ra khỏi lớp. Bạn có thể chọn định nghĩa hàm nào là một phần của mô-đun và định nghĩa nào không.


8

Điều này đến từ P1779 , mới được thông qua ở Prague vài ngày trước. Từ đề xuất:

Bài viết này đề xuất loại bỏ trạng thái nội tuyến ẩn khỏi các hàm được định nghĩa trong định nghĩa lớp được đính kèm với mô-đun (được đặt tên). Điều này cho phép các lớp được hưởng lợi từ việc tránh các khai báo dư thừa, duy trì tính linh hoạt được cung cấp cho các tác giả mô-đun trong việc khai báo các hàm có hoặc không có nội tuyến. Hơn nữa, nó cho phép bạn bè của các mẫu lớp (không thể được định nghĩa chung bên ngoài định nghĩa lớp) hoàn toàn không phải là nội tuyến. Nó cũng giải quyết NB bình luận US90 .

Bài báo (trong số những thứ khác) loại bỏ câu:

Một hàm được định nghĩa trong một định nghĩa lớp là một hàm nội tuyến.

và thêm câu:

Trong mô-đun toàn cầu, một hàm được định nghĩa trong một định nghĩa lớp là ngầm định nội tuyến ([class.mfct], [class.friend]).


Ví dụ của bạn với export module Msẽ là tương đương mô-đun của chương trình ban đầu. Lưu ý rằng trình biên dịch đã thực hiện các hàm nội tuyến không được chú thích inline, chỉ là chúng sử dụng thêm sự hiện diện của inlinetừ khóa trong các heuristic của chúng.


Vì vậy, một chức năng trong một mô-đun không có inlinetừ khóa sẽ không bao giờ được trình biên dịch nội tuyến, đúng không?
metalfox

1
@metalfox Không, tôi không tin đó là chính xác.
Barry

1
Tôi hiểu rồi. Cảm ơn. Nó giống như được định nghĩa trong tệp cpp, điều đó không nhất thiết có nghĩa là nó sẽ không được nội tuyến tại thời điểm liên kết.
metalfox
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.