Tại sao <T> được mong đợi trong LLVM triển khai hai hàm tạo cho <T> &&?


8

Expected<T>được triển khai trong llvm / Support / Error.h. Đó là một liên minh được gắn thẻ giữ một Thoặc một Error.

Expected<T>là một lớp mẫu với loại T:

template <class T> class LLVM_NODISCARD Expected

Nhưng hai nhà xây dựng này thực sự làm tôi bối rối:

  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
  /// must be convertible to T.
  template <class OtherT>
  Expected(Expected<OtherT> &&Other,
           typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
               * = nullptr) {
    moveConstruct(std::move(Other));
  }

  /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
  /// isn't convertible to T.
  template <class OtherT>
  explicit Expected(
      Expected<OtherT> &&Other,
      typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
          nullptr) {
    moveConstruct(std::move(Other));
  }

Tại sao Expected<T>lặp lại hai cấu trúc cho cùng thực hiện? Tại sao nó không làm như thế này?:

template <class OtherT>
Expected(Expected<OtherT>&& Other) { moveConstruct(std::move(Other));}

1
Lưu ý explicittừ khóa
Mat

Tôi muốn biết tại sao explicittừ khóa quan trọng ở đây? Bất cứ ai có thể đưa ra một ví dụ?
yodahaji

Câu trả lời:


8

Bởi vì nhà xây dựng đó là điều kiện rõ ràng theo đề xuất. Điều này có nghĩa là hàm tạo chỉ rõ ràng nếu một số điều kiện được đáp ứng (ở đây, khả năng chuyển đổi của TOtherT).

C ++ không có cơ chế cho chức năng này (một cái gì đó explicit(condition)) trước C ++ 20. Do đó, việc triển khai cần sử dụng một số cơ chế khác, chẳng hạn như định nghĩa của hai hàm tạo khác nhau - một rõ ràng và một chuyển đổi khác - và đảm bảo lựa chọn hàm tạo thích hợp theo điều kiện. Điều này thường được thực hiện thông qua SFINAE với sự giúp đỡ của std::enable_if, trong đó điều kiện được giải quyết.


Kể từ C ++ 20, cần có một phiên bản có điều kiện của explicitspecifier. Việc thực hiện sau đó sẽ dễ dàng hơn nhiều với một định nghĩa duy nhất:

template <class OtherT>
explicit(!std::is_convertible_v<OtherT, T>)
Expected(Expected<OtherT> &&Other)
{
   moveConstruct(std::move(Other));
}

Cảm ơn câu trả lời của bạn. Mặc dù tôi vẫn còn bối rối, tôi đã nhận được rất nhiều tài nguyên sau khi googling 'rõ ràng có điều kiện'.
yodahaji

@yodahaji Lưu ý rằng điều kiện rõ ràng không phải là một thuật ngữ tiêu chuẩn. Nó đơn giản có nghĩa là hàm tạo rõ ràng hoặc chuyển đổi theo một số điều kiện.
Daniel Langr

5

Để hiểu điều này chúng ta nên bắt đầu với std::is_convertible. Theo cppreference :

Nếu định nghĩa hàm tưởng tượng được định dạng To test() { return std::declval<From>(); }tốt, (nghĩa là, có std::declval<From>()thể được chuyển đổi sang Tosử dụng chuyển đổi ngầm định hoặc cả hai FromTocó thể là khoảng trống đủ điều kiện cv), cung cấp giá trị hằng số thành viên bằng true. Nếu không thì giá trị là false. Đối với mục đích của kiểm tra này, việc sử dụng std::declvaltrong tuyên bố hoàn trả không được coi là sử dụng odr.

Kiểm tra truy cập được thực hiện như thể từ một bối cảnh không liên quan đến một trong hai loại. Chỉ tính hợp lệ của ngữ cảnh ngay lập tức của biểu thức trong câu lệnh return (bao gồm cả chuyển đổi sang kiểu trả về) mới được xem xét.

Phần quan trọng ở đây là nó chỉ kiểm tra các chuyển đổi ngầm định. Do đó, hai cách triển khai trong OP của bạn có nghĩa là nếu OtherTđược chuyển đổi hoàn toàn sang T, thì expected<OtherT>nó hoàn toàn có thể chuyển đổi thành expected<T>. Nếu OtherTyêu cầu một diễn viên rõ ràng đến T, sau đó Expected<OtherT>yêu cầu và diễn viên rõ ràng đến Expected<T>.

Dưới đây là ví dụ về các diễn viên ngầm và rõ ràng và các Expectedđối tác của họ

int x;
long int y = x;              // implicit cast ok
Expected<int> ex;
Expected<long int> ey = ex;  // also ok

void* v_ptr;
int* i_ptr = static_cast<int*>(v_ptr);              // explicit cast required
Expected<void*> ev_ptr;
auto ei_ptr = static_cast<Expected<int*>>(ev_ptr);  // also required

Cảm ơn câu trả lời của bạn. Nhưng tôi không thể hiểu ý nghĩa của 'sau đó Expected<OtherT>yêu cầu diễn viên rõ ràng Expected<T>có nghĩa'. "Diễn viên rõ ràng" ở đây có nghĩa là gì? Tôi không thể hình dung một ví dụ cho điều này.
yodahaji

Đã thêm một vài ví dụ vào bài đăng để làm rõ ý nghĩa rõ ràng của phôi. Nói chung, chúng được sử dụng để ngăn chặn các diễn viên ngầm vô tình khi chúng có thể gây ra lỗi. Thật không may, tôi không thể kiểm tra mã ngay bây giờ vì vậy nếu bạn phát hiện ra lỗi chính tả / lỗi, vui lòng cho tôi biết và tôi sẽ sửa nó.
patatahooligan

Tuyên bố này 'để ngăn chặn các diễn viên vô tình' trả lời câu hỏi của tôi. Cảm ơn bạn :)
yodahaji
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.