ปัญหาภาษาแปลกคือCWG 1581 :
ข้อ 15 [พิเศษ] มีความชัดเจนอย่างสมบูรณ์แบบว่าฟังก์ชั่นสมาชิกพิเศษมีการกำหนดโดยนัยเฉพาะเมื่อพวกเขาถูกใช้งาน สิ่งนี้สร้างปัญหาสำหรับนิพจน์คงที่ในบริบทที่ไม่ได้ประเมินค่า:
struct duration {
constexpr duration() {}
constexpr operator int() const { return 0; }
};
// duration d = duration(); // #1
int n = sizeof(short{duration(duration())});
ปัญหาที่นี่คือเราไม่ได้รับอนุญาตให้กำหนดโดยปริยายconstexpr duration::duration(duration&&)
ในโปรแกรมนี้ดังนั้นการแสดงออกในรายการ initializer ไม่ใช่การแสดงออกคงที่ (เพราะมันจะเรียกใช้ฟังก์ชั่น constexpr ซึ่งยังไม่ได้กำหนด) ดังนั้น initializer braced มีการแปลงแคบ ดังนั้นโปรแกรมจึงมีรูปแบบไม่ดี
หากเราไม่ใส่เครื่องหมายบรรทัด # 1 ตัวสร้างการย้ายจะถูกกำหนดโดยปริยายและโปรแกรมนั้นจะถูกต้อง การกระทำที่น่ากลัวในระยะนี้เป็นเรื่องที่โชคร้ายอย่างยิ่ง การใช้งานแตกต่างในจุดนี้
คุณสามารถอ่านคำอธิบายปัญหาที่เหลือ
การแก้ไขปัญหานี้ถูกนำมาใช้ในP0859ใน Albuquerque ในปี 2560 (หลังจากจัดส่ง C ++ 17) ปัญหานั้นเป็นตัวบล็อกสำหรับทั้งสองสามารถมีconstexpr std::swap
(แก้ไขในP0879 ) และconstexpr std::invoke
(แก้ไขในP1065ซึ่งมีตัวอย่าง CWG1581 ด้วย) ทั้งสำหรับ C ++ 20
ตัวอย่างที่เข้าใจง่ายที่สุดในความคิดของฉันคือรหัสจากรายงานข้อผิดพลาด LLVM ที่ระบุใน P1065:
template<typename T>
int f(T x)
{
return x.get();
}
template<typename T>
constexpr int g(T x)
{
return x.get();
}
int main() {
// O.K. The body of `f' is not required.
decltype(f(0)) a;
// Seems to instantiate the body of `g'
// and results in an error.
decltype(g(0)) b;
return 0;
}
CWG1581 เป็นข้อมูลเกี่ยวกับเมื่อฟังก์ชันสมาชิก constexpr มีการกำหนดและสร้างความมั่นใจความละเอียดที่พวกเขากำลังที่กำหนดไว้เท่านั้นเมื่อนำมาใช้ หลังจาก P0859 ข้างต้นจะเกิดขึ้นอย่างดี (ประเภทของb
คือint
)
เนื่องจากstd::swap
และstd::invoke
ทั้งคู่ต้องพึ่งพาการตรวจสอบฟังก์ชั่นสมาชิก (ย้ายการก่อสร้าง / การมอบหมายในอดีตและผู้ดำเนินการโทร / การโทรตัวแทนในภายหลัง) พวกเขาทั้งสองขึ้นอยู่กับการแก้ไขปัญหานี้