ประเภทที่ไม่ระบุสามารถใช้ในนิพจน์ 'ต้องใช้' ของ C ++ 20 ได้อย่างไร
ฉันพยายามเขียนแนวคิด C ++ 20 เพื่อแสดงความต้องการว่าประเภทมีวิธีการบางอย่างซึ่งใช้เวลาโต้แย้ง แต่สำหรับวัตถุประสงค์ของแนวคิดนี้ฉันไม่สนใจว่าประเภทอาร์กิวเมนต์คืออะไร
ฉันพยายามเขียนสิ่งที่ชอบ:
template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
อย่างไรก็ตามทั้ง gcc และ clang ปฏิเสธสิ่งนี้ทำให้เกิดข้อผิดพลาดที่ไม่สามารถใช้ 'auto' ในรายการพารามิเตอร์ของนิพจน์ที่ต้องการด้วยวิธีนี้
อีกทางเลือกหนึ่งคือการใส่ประเภท 'x' เป็นพารามิเตอร์เทมเพลตที่สอง:
template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
แต่สิ่งนี้จำเป็นต้องระบุ TX อย่างชัดเจนเมื่อใดก็ตามที่ใช้แนวคิดนี้จะไม่สามารถอนุมานได้:
struct S { void Foo(int); };
static_assert(HasFooMethod<S>); // doesn't compile
static_assert(HasFooMethod<S, int>); // the 'int' must be specified
มีวิธีใดในการเขียนแนวคิดที่อนุญาตให้ Foo โต้แย้งประเภทที่ไม่ระบุ ?
คำจำกัดความแนวคิดของคำถามที่ต้องการฟังก์ชันสมาชิกเทมเพลตที่มีข้อ จำกัดนั้นคล้ายกันมาก แต่ไม่เหมือนกัน: คำถามนั้นถามว่าต้องการให้เมธอด (เทมเพลต) สามารถใช้ประเภทใดก็ได้ที่ตรงตามแนวคิดที่กำหนดในขณะที่คำถามนี้เกี่ยวกับการกำหนดให้ใช้วิธีการบางประเภทโดยเฉพาะแม้ว่าประเภทนั้นจะไม่ระบุก็ตาม ในแง่ของตัวระบุจำนวนคำถามอีกข้อคือถามเกี่ยวกับการหาปริมาณสากล (ขอบเขต) ในขณะที่คำถามนี้เกี่ยวกับการหาปริมาณที่มีอยู่จริง คำตอบของคำถามอื่นใช้ไม่ได้กับกรณีของฉัน
คำตอบ
แนวคิดไม่ได้มีจุดมุ่งหมายเพื่อจัดหาฟังก์ชันการทำงานที่คุณต้องการ ดังนั้นพวกเขาจึงไม่ให้มัน
แนวคิดมีขึ้นเพื่อ จำกัด เทมเพลตเพื่อระบุชุดของนิพจน์หรือคำสั่งที่เทมเพลตตั้งใจจะใช้ (หรืออย่างน้อยก็มีอิสระที่จะใช้) ในคำจำกัดความ
ภายในเทมเพลตที่คุณ จำกัด ไว้มากถ้าคุณเขียนนิพจน์t.Foo(x)
คุณก็จะรู้ประเภทของx
. เป็นประเภทคอนกรีตพารามิเตอร์เทมเพลตหรือชื่อที่ได้มาจากพารามิเตอร์เทมเพลต ไม่ว่าจะด้วยวิธีใดประเภทของx
จะมีอยู่ในเทมเพลตที่ถูก จำกัด
ดังนั้นหากคุณต้องการ จำกัด เทมเพลตดังกล่าวคุณใช้ทั้งประเภทของt
และประเภทของx
. คุณสามารถใช้ทั้งสองอย่างได้ในเวลานั้นดังนั้นจึงไม่มีปัญหาในการสร้างข้อ จำกัด ดังกล่าว นั่นคือข้อ จำกัด ไม่ได้อยู่T
ในประเภทที่แยกได้ มันเป็นเรื่องเกี่ยวกับความสัมพันธ์ระหว่างและT
X
แนวคิดไม่ได้หมายถึงการทำงานในสุญญากาศโดยปราศจากความเกี่ยวข้องใด ๆ กับสถานที่จริงของการใช้ข้อ จำกัด คุณไม่ควรมุ่งเน้นไปที่การสร้างแนวคิดที่เป็นเอกภาพเพื่อให้ผู้ใช้สามารถstatic_assert
ต่อต้านแนวคิดเหล่านี้ได้ แนวคิดไม่ได้มีไว้สำหรับการทดสอบว่าประเภทใดตอบสนองพวกเขาได้ (ซึ่งโดยพื้นฐานแล้วสิ่งที่คุณstatic_assert
กำลังทำอยู่) พวกเขากำลังหมายสำหรับ constraining นิยามแม่แบบที่ใช้พวกเขา
ความต้องการข้อ จำกัด ของคุณจะไม่ได้FooCallableWith
HasFooMethod
สิ่งที่ใกล้เคียงกับสิ่งนี้สามารถทำได้โดยการกำหนดประเภทอะแดปเตอร์ที่สามารถแปลงเป็น (เกือบ) อะไรโดยปริยาย:
struct anything
{
// having both these conversions allows Foo's argument to be either
// a value, an lvalue reference, or an rvalue reference
template <typename T>
operator T&();
template <typename T>
operator T&&();
};
โปรดทราบว่าไม่จำเป็นต้องใช้ตัวดำเนินการเหล่านี้เนื่องจากจะใช้ในบริบทที่ไม่ได้ประเมินเท่านั้น (และไม่สามารถนำไปใช้กับ T ทุกประเภทได้)
จากนั้นHasFooMethod
สามารถเขียนเป็น:
template <typename T>
concept HasFooMethod = requires(T t, anything a)
{
{ t.Foo(a) } -> std::same_as<void>;
};