C ++ 20 Concepts: ความเชี่ยวชาญเทมเพลตใดที่ได้รับเลือกเมื่ออาร์กิวเมนต์เทมเพลตนั้นมีคุณสมบัติเหมาะสมสำหรับหลายแนวคิด


23

ให้:

#include <concepts>
#include <iostream>

template<class T>
struct wrapper;

template<std::signed_integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "signed_integral" << std::endl;
    }
};

template<std::integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "integral" << std::endl;
    }
};

int main()
{
    wrapper<int> w;
    w.print(); // Output : signed_integral
    return 0;
}

จากรหัสด้านบนintมีคุณสมบัติทั้งstd::integralและstd::signed_integralแนวคิด

น่าประหลาดใจที่คอมไพล์และพิมพ์ "ลงนาม _integral" บนคอมไพเลอร์ GCC และ MSVC ฉันคาดหวังว่ามันจะล้มเหลวโดยมีข้อผิดพลาดตามบรรทัดของ "การกำหนดแม่แบบเฉพาะทางแล้ว"

เอาล่ะที่กฎหมายยุติธรรมพอ แต่ทำไมstd::signed_integralได้รับการแต่งตั้งแทนstd::integral? มีกฎใดที่กำหนดไว้ในมาตรฐานพร้อมกับเลือกแม่แบบเฉพาะทางเมื่อแนวคิดหลายอย่างมีคุณสมบัติเหมาะสมสำหรับอาร์กิวเมนต์ของแม่แบบหรือไม่


ฉันจะไม่พูดว่ามันถูกกฎหมายเพียงเพราะคอมไพเลอร์ (s) ยอมรับมันโดยเฉพาะอย่างยิ่งในช่วงเริ่มต้นของการยอมรับมัน
สลาวา

@ Slava ในกรณีนี้คือแนวคิดได้รับการออกแบบอย่างรอบคอบเพื่อให้พวกเขาแบ่งปันซึ่งกันและกันในลักษณะที่ใช้งานง่าย
Guillaume Racicot

@ GuillaumeRacicot มันเป็นเรื่องปกติฉันเพียงแค่ให้ความเห็นว่าข้อสรุป "มันถูกกฎหมายเพราะคอมไพเลอร์ยอมรับมัน" เป็นคำพูดที่ทำให้เข้าใจผิด ฉันไม่ได้บอกว่ามันไม่ถูกกฎหมาย
สลาวา

คำตอบ:


14

นี่เป็นเพราะแนวคิดสามารถมีความเชี่ยวชาญได้มากกว่าผู้อื่นเช่นเดียวกับที่เทมเพลตสั่งซื้อเอง สิ่งนี้เรียกว่าการเรียงลำดับข้อ จำกัด บางส่วน

ในกรณีของแนวความคิดพวกเขาย่อยซึ่งกันและกันเมื่อพวกเขามีข้อ จำกัด ที่เทียบเท่า ตัวอย่างเช่นต่อไปนี้เป็นวิธีการstd::integralและstd::signed_integralนำไปใช้งาน:

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T> //   v--------------v---- Using the contraint defined above
concept signed_integral = std::integral<T> && std::is_signed_v<T>;

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

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T>
concept signed_integral = std::is_integral_v<T> && std::is_signed_v<T>;

ในตัวอย่างนี้มีsigned_integralความหมายintegralอย่างสมบูรณ์ ดังนั้นในแง่หนึ่งอินทิกรัลที่เซ็นชื่อคือ "ถูก จำกัด มากขึ้น" มากกว่าอินทิกรัล

มาตรฐานเขียนแบบนี้:

จาก[temp.func.order] / 2 (เน้นที่เหมือง):

การสั่งซื้อบางส่วนเลือกว่าฟังก์ชันใดของแม่แบบที่สองซึ่งมีความเชี่ยวชาญมากกว่าแบบอื่นโดยเปลี่ยนแต่ละเทมเพลตตามลำดับ (ดูย่อหน้าถัดไป) และดำเนินการลดอาร์กิวเมนต์เทมเพลตโดยใช้ประเภทฟังก์ชัน กระบวนการหักเงินกำหนดว่าแม่แบบใดแบบหนึ่งมีความเชี่ยวชาญมากกว่าแบบอื่น ถ้าเป็นเช่นนั้นเทมเพลตที่พิเศษกว่านั้นคือเทมเพลตที่ถูกเลือกโดยกระบวนการสั่งซื้อบางส่วน หากทั้งสองหักเงินประสบความสำเร็จบางส่วนการสั่งซื้อเลือกแม่แบบ จำกัด มากขึ้นตามที่อธิบายไว้ตามกฎใน[temp.constr.order]

นั่นหมายความว่าหากมีการทดแทนได้หลายแบบสำหรับเทมเพลตและทั้งคู่เลือกจากการสั่งซื้อบางส่วนก็จะเลือกเทมเพลตที่มีข้อ จำกัด มากที่สุด

จาก[temp.constr.order] / 1 :

ข้อ จำกัดP subsumesจำกัดQถ้าหากว่าสำหรับทุกลักษณะที่แยกประโยคP ผมในรูปแบบปกติของลักษณะที่แยกออกP , P ฉัน subsumes ทุกที่เชื่อมต่อข้อถามเจในรูปแบบปกติที่เชื่อมต่อกันของQที่

  • disjunctive ข้อP ฉัน subsumes เชื่อมต่อข้อถามเจและถ้าหากมีอยู่ จำกัด อะตอมP IAในP ฉันที่มีอยู่ จำกัด อะตอมQ JBในQ ดังกล่าวว่าP IA subsumes Q JBและ

  • อะตอม จำกัดsubsumes อีก จำกัด อะตอมBถ้าหากและBเหมือนกันโดยใช้กฎที่อธิบายไว้ใน[temp.constr.atomic]

สิ่งนี้อธิบายถึงอัลกอริธึม subsumption ที่คอมไพเลอร์ใช้เพื่อจัดเรียงข้อ จำกัด และแนวคิดดังนั้น


2
ดูเหมือนว่าคุณกำลังลากเส้นอยู่กลางย่อหน้า ...
ShadowRanger

11

C ++ 20 มีกลไกสำหรับการตัดสินใจเมื่อเอนทิตีที่ จำกัด อย่างใดอย่างหนึ่งคือ "จำกัด มากขึ้น" มากกว่าเอนทิตีอื่น นี่ไม่ใช่เรื่องง่าย

เริ่มต้นนี้กับแนวคิดของการที่จะหมดลง จำกัด เป็นส่วนประกอบอะตอมซึ่งเป็นกระบวนการที่เรียกว่าข้อ จำกัด การฟื้นฟู มันใหญ่และซับซ้อนเกินกว่าจะเข้าไปที่นี่ได้ แต่แนวคิดพื้นฐานคือแต่ละนิพจน์ในข้อ จำกัด นั้นแบ่งออกเป็นชิ้นส่วนแนวคิดอะตอมของมันซ้ำ ๆ จนกว่าคุณจะถึงส่วนประกอบย่อยที่ไม่ใช่แนวคิด

จากนั้นให้ดูที่วิธีการintegralและsigned_integralแนวคิดที่กำหนด :

template<class T>
  concept integral = is_integral_v<T>;
template<class T>
  concept signed_­integral = integral<T> && is_signed_v<T>;

การสลายตัวของเป็นเพียงintegral is_integral_vการสลายตัวของมีsigned_integralis_integral_v && is_signed_v

ตอนนี้เรามาถึงแนวคิดของข้อ จำกัด การย่อย มันค่อนข้างซับซ้อน แต่ความคิดพื้นฐานคือข้อ จำกัด C1 ถูกกล่าวถึง "subsume" ข้อ จำกัด C2 หากการสลายตัวของ C1 มีทุกนิพจน์ย่อยใน C2 เราจะเห็นว่าintegralไม่ subsume signed_integralแต่signed_integral ไม่ subsume integralเพราะมันมีทุกสิ่งที่integralทำ

ต่อไปเรามาสั่งซื้อเอนทิตีที่ จำกัด :

การประกาศ D1 อย่างน้อยที่สุดก็เป็นข้อ จำกัด เหมือนกับการประกาศ D2 ถ้า * D1 และ D2 เป็นทั้งการประกาศแบบ จำกัด และข้อ จำกัด ที่เกี่ยวข้องของ D1 จะรวมอยู่ในการประกาศ D2 หรือ * D2 ไม่มีข้อ จำกัด ที่เกี่ยวข้อง

เพราะsigned_integralsubsumes integralที่<signed_integral> wrapperเป็น "อย่างน้อยเป็นข้อ จำกัด" <integral> wrapperเป็น อย่างไรก็ตามการย้อนกลับไม่เป็นความจริงเนื่องจากการ subsumption ไม่สามารถย้อนกลับได้

ดังนั้นตามกฎสำหรับเอนทิตี "ที่ จำกัด มากขึ้น":

การประกาศ D1 มีข้อ จำกัด มากกว่าการประกาศอื่น D2 เมื่อ D1 มีข้อ จำกัด อย่างน้อยเท่ากับ D2 และอย่างน้อย D2 จะไม่ถูก จำกัด เท่ากับ D1

เนื่องจาก<integral> wrapperข้อ จำกัด ดังกล่าวไม่ได้เป็นอย่างน้อย<signed_integral> wrapperจึงถือว่าเป็นข้อ จำกัด ที่มากกว่าข้อ จำกัด เดิม

ดังนั้นเมื่อทั้งสองคนสามารถใช้งานได้การประกาศที่มีข้อ จำกัด มากขึ้นก็จะชนะ


โปรดทราบว่ากฎของ subsumption จำกัดหยุดconceptเมื่อมีการแสดงออกจะพบซึ่งไม่ได้เป็น ดังนั้นหากคุณทำสิ่งนี้:

template<typename T>
constexpr bool my_is_integral_v = std::is_integral_v<T>;

template<typename T>
concept my_signed_integral = my_is_integral_v<T> && std::is_signed_v<T>;

ในกรณีนี้my_signed_integral จะไม่std::integral subsume แม้ว่าจะmy_is_integral_vมีการกำหนดเหมือนกันstd::is_integral_vเนื่องจากไม่ใช่แนวคิดกฎการปันส่วนของ C ++ ไม่สามารถตรวจสอบได้เพื่อตรวจสอบว่ากฎนั้นเหมือนกัน

ดังนั้นกฎการสนับสนุนให้คุณสร้างแนวคิดจากการดำเนินการตามแนวคิดอะตอมมิก


3

ด้วยPartial_ordering_of_constraints

มีการกล่าวถึงข้อ จำกัด ของ P เพื่อ จำกัด ข้อ จำกัด Q หากสามารถพิสูจน์ได้ว่า P บอกเป็นนัยถึงความเป็นตัวตนของข้อ จำกัด อะตอมใน P และ Q

และ

ความสัมพันธ์ Subsumption กำหนดลำดับของข้อ จำกัด บางส่วนซึ่งใช้เพื่อกำหนด:

  • ผู้สมัครที่ทำงานได้ดีที่สุดสำหรับฟังก์ชั่นที่ไม่ใช่แม่แบบในการแก้ปัญหาเกินพิกัด
  • ที่อยู่ของฟังก์ชั่นที่ไม่ใช่แม่แบบในชุดเกินพิกัด
  • คู่ที่ดีที่สุดสำหรับอาร์กิวเมนต์แม่แบบ
  • การสั่งซื้อบางส่วนของความเชี่ยวชาญแม่แบบชั้นเรียน
  • การสั่งซื้อบางส่วนของแม่แบบฟังก์ชั่น

และแนวคิดแนวคิดstd::signed_integralย่อยstd::integral<T>:

template < class T >
concept signed_integral = std::integral<T> && std::is_signed_v<T>;

ดังนั้นรหัสของคุณก็โอเคเช่นเดียวกับstd::signed_integral"พิเศษ" มากกว่า

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