usecase คืออะไรสำหรับชัดแจ้ง (บูล)


24

C ++ 20 แนะนำชัดแจ้ง (บูล)ซึ่งเลือกตามเงื่อนไขในเวลาคอมไพล์ไม่ว่าคอนสตรัคเตอร์จะถูกสร้างขึ้นมาอย่างชัดเจนหรือไม่

ด้านล่างเป็นตัวอย่างที่ผมพบว่าที่นี่

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

ใครสามารถบอก usecase อื่น ๆ ให้ฉันได้explicit (bool)นอกจากใช้std::is_integral?


1
ตัวอย่างหนึ่งคือมันง่ายกว่ามากที่จะใช้ Constructor ที่ชัดเจนตามเงื่อนไขเช่นเดียวtupleกับที่ใช้กับคุณลักษณะนี้
Praetorian

1
ไม่ใช่คำตอบที่ถูกต้อง แต่คุณสามารถดูแรงจูงใจในบทความที่แนะนำ: wg21.link/p0892
N. Shead

ตัวอย่าง: มัน (พร้อมกับแนวคิด) ลดจำนวนคลาสพื้นฐานที่ต้องการลงเพื่อสร้างตัวสร้างสำเนาที่มีเงื่อนไขที่กำหนดเงื่อนไขจาก 3 ถึง 0
LF

คำตอบ:


21

แรงจูงใจในตัวเองสามารถมองเห็นได้ในกระดาษ

ไม่จำเป็นต้องสร้างคอนสตรัคเตอร์อย่างมีเงื่อนไข นั่นคือคุณต้องการ:

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

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

อดีตเป็นเรื่องปกติผู้สร้างเหล่านั้นโดยปริยาย explicitแต่หลังจะไม่ดีเหล่านั้นมีการก่อสร้าง ด้วย C ++ 17 (หรือ C ++ 20 ที่มีแนวคิด) วิธีเดียวที่จะทำให้งานนี้คือการเขียนตัวสร้างสอง - หนึ่งexplicitและหนึ่งไม่:

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&& );    
};  

สิ่งเหล่านี้ซ้ำกันเกือบทั้งหมด - และคำจำกัดความของตัวสร้างเหล่านี้จะเหมือนกัน

ด้วยexplicit(bool), คุณสามารถเขียนคอนสตรัคเตอร์เดียวได้ - ด้วยส่วนที่ชัดเจนตามเงื่อนไขของสิ่งก่อสร้างที่แปลเป็น "ตัวระบุ" explicit:

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&& );   
};

สิ่งนี้ตรงกับเจตนาที่ดีกว่าคือมีโค้ดน้อยกว่าในการเขียนและทำงานได้น้อยกว่าสำหรับคอมไพเลอร์ที่ต้องทำในระหว่างการแก้ปัญหาโอเวอร์โหลด


1
C ++ 20 ยังให้ความสามารถในการเปลี่ยนชิ้นenable_if_tส่วนให้เป็นข้อ จำกัด ที่สวยงามและเรียบง่ายขึ้นซึ่งอาจใช้แนวคิด แต่นั่นเป็นประเด็นของคำถามนี้
aschepler

2

การใช้ที่เป็นไปได้อีกอย่างที่ฉันเห็นคือเทมเพลต Variadic

โดยปกติแล้วจะดีexplicitสำหรับผู้สร้างที่มีอาร์กิวเมนต์เดียวเท่านั้น (เว้นแต่ว่าต้องการการแปลง)

ดังนั้น

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

    // ...
};

0

ฉันสามารถดูกรณีการใช้งานสำหรับการกำหนดexplicitเงื่อนไขเมื่ออินพุตอาจเป็นประเภทมุมมอง (ตัวชี้แบบดิบstd::string_view) ที่วัตถุใหม่จะยังคงอยู่หลังจากการโทร (คัดลอกมุมมองเท่านั้นไม่ใช่สิ่งที่มันหมายถึงที่เหลือขึ้นอยู่กับ อายุการใช้งานของวัตถุที่ดู) หรืออาจเป็นประเภทที่มีมูลค่าเหมือนกัน (เป็นเจ้าของสำเนาโดยไม่มีการอ้างอิงอายุการใช้งานภายนอก)

ในสถานการณ์เช่นนั้นผู้เรียกต้องรับผิดชอบในการทำให้วัตถุที่ดูยังมีชีวิตอยู่ (ผู้ที่เป็นเจ้าของมุมมองไม่ใช่วัตถุดั้งเดิม) และการแปลงไม่ควรกระทำโดยปริยายเพราะทำให้ง่ายเกินไปสำหรับวัตถุที่สร้างขึ้นโดยปริยาย อยู่ได้นานกว่าวัตถุที่มันดู ในทางกลับกันสำหรับประเภทค่าวัตถุใหม่จะได้รับสำเนาของตัวเองดังนั้นในขณะที่สำเนาอาจมีค่าใช้จ่ายสูงมันจะไม่ทำให้โค้ดผิดหากมีการแปลงโดยนัย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.