usecase cho tường minh (bool) là gì


24

C ++ 20 đã giới thiệu tường minh (bool) có điều kiện chọn tại thời điểm biên dịch cho dù một hàm tạo có được làm rõ hay không.

Dưới đây là một ví dụ mà tôi tìm thấy ở đây .

struct foo {

  // Specify non-integral types (strings, floats, etc.) require explicit construction.

  template <typename T>

  explicit(!std::is_integral_v<T>) foo(T) {}

};

foo a = 123; // OK

foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit specifier evaluates to true)

foo c {"123"}; // OK

Bất cứ ai có thể cho tôi biết bất kỳ usecase nào explicit (bool)khác ngoài việc sử dụng std::is_integral?


1
Một ví dụ là nó trở nên dễ dàng hơn rất nhiều để thực hiện các hàm tạo rõ ràng có điều kiện như các hàm tạo tuplevới tính năng này.
Praetorian

1
Không phải là một câu trả lời thích hợp, nhưng bạn cũng có thể nhìn vào động lực trong bài báo đã giới thiệu nó: wg21.link/p0892
N. Shead

Ví dụ: nó (cùng với các khái niệm) cắt giảm số lượng các lớp cơ sở cần thiết để triển khai một hàm tạo sao chép rõ ràng có điều kiện được cung cấp có điều kiện từ 3 đến 0.
LF

Câu trả lời:


21

Động lực chính nó có thể được nhìn thấy trong bài báo .

Có một nhu cầu để làm cho các nhà xây dựng có điều kiện rõ ràng. Đó là, bạn muốn:

pair<string, string> safe() {
    return {"meow", "purr"}; // ok
}

pair<vector<int>, vector<int>> unsafe() {
    return {11, 22}; // error
}

Các cựu là tốt, những nhà xây dựng là ẩn. Nhưng sau này sẽ là xấu, những nhà xây dựng là explicit. Với C ++ 17 (hoặc C ++ 20 với các khái niệm), cách duy nhất để thực hiện công việc này là viết hai hàm tạo - một explicitvà một không:

template <typename T1, typename T2>
struct pair {
    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2> &&
            std::is_convertible_v<U1, T1> &&
            std::is_convertible_v<U2, T2>
        , int> = 0>
    constexpr pair(U1&&, U2&& );

    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2> &&
            !(std::is_convertible_v<U1, T1> &&
              std::is_convertible_v<U2, T2>)
        , int> = 0>
    explicit constexpr pair(U1&&, U2&& );    
};  

Chúng gần như hoàn toàn trùng lặp - và định nghĩa của các hàm tạo này sẽ giống hệt nhau.

Với explicit(bool), bạn chỉ có thể viết một hàm tạo duy nhất - với phần rõ ràng có điều kiện của cấu trúc được bản địa hóa thành chỉ explicit-specifier:

template <typename T1, typename T2>
struct pair {
    template <typename U1=T1, typename U2=T2,
        std::enable_if_t<
            std::is_constructible_v<T1, U1> &&
            std::is_constructible_v<T2, U2>
        , int> = 0>
    explicit(!std::is_convertible_v<U1, T1> ||
        !std::is_convertible_v<U2, T2>)
    constexpr pair(U1&&, U2&& );   
};

Điều này phù hợp với ý định tốt hơn, viết mã ít hơn nhiều và công việc của trình biên dịch sẽ ít hơn trong quá trình giải quyết quá tải (vì có ít hàm tạo hơn phải chọn giữa).


1
C ++ 20 cũng cung cấp khả năng thay đổi enable_if_tphần thành một ràng buộc đẹp hơn và đơn giản hơn, có thể sử dụng các khái niệm. Nhưng đó là bên cạnh điểm của câu hỏi này.
aschepler

2

Một cách sử dụng khác có thể tôi thấy là với mẫu matrixdic:

Theo mặc định, điều này tốt explicitcho nhà xây dựng chỉ với một đối số (trừ khi chuyển đổi là mong muốn).

vì thế

struct Foo
{
    template <typename ... Ts>
    explicit(sizeof...(Ts) == 1) Foo(Ts&&...);

    // ...
};

0

Tôi có thể thấy trường hợp sử dụng để yêu cầu có explicitđiều kiện khi đầu vào có thể là kiểu giống như khung nhìn (con trỏ thô std::string_view) mà đối tượng mới sẽ giữ sau cuộc gọi (chỉ sao chép chế độ xem, không phải là nội dung mà nó đề cập, còn phụ thuộc vào thời gian tồn tại của đối tượng được xem) hoặc có thể là loại giống như giá trị (sở hữu bản sao, không có phụ thuộc trọn đời bên ngoài).

Trong tình huống như vậy, người gọi có trách nhiệm giữ cho đối tượng được xem còn sống (callee sở hữu chế độ xem chứ không phải đối tượng ban đầu) và việc chuyển đổi không nên được thực hiện một cách ngầm định, vì nó quá dễ dàng cho đối tượng được tạo ngầm tồn tại lâu hơn đối tượng mà nó xem. Ngược lại, đối với các loại giá trị, đối tượng mới sẽ nhận được bản sao của chính nó, vì vậy trong khi bản sao có thể tốn kém, nó sẽ không làm cho mã sai nếu xảy ra chuyển đổi ngầm.

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.