std :: is_constructible ส่งคืนค่าที่ไม่สอดคล้องกันสำหรับตัวสร้างส่วนตัว


13

อะไรคือกฎที่ใช้ในการstd::is_constructibleก่อสร้างส่วนตัว? รับรหัสต่อไปนี้:

#include <iostream>

class Class {
private:
    Class() { }
};

template <typename T>
class Test {
public:
    static void test() {
        std::cout
            //<< std::is_constructible<Class>::value
            << std::is_constructible<T>::value
            << std::endl;
    }
};

int main() {
    Test<Class>::test();
}

ภาพพิมพ์นี้0( ideone ) Tคือไม่สามารถกำหนดค่าเริ่มต้นได้

ไม่ใส่เครื่องหมายในบรรทัดที่คอมเม้นต์มันจะพิมพ์11( ideone ) ดังนั้นจึงTกลายเป็นค่าเริ่มต้นที่สามารถสร้างได้

ฉันสามารถหาเหตุผลในการสนับสนุนผลลัพธ์ทั้งสอง แต่ฉันไม่เข้าใจว่าการรวมบรรทัดที่ถูกคอมเม้นต์นั้นเปลี่ยนแปลงผลลัพธ์ของวินาทีได้อย่างไร นี่คือสิ่งที่เรียก UB หรือไม่? นี่เป็นข้อผิดพลาดของคอมไพเลอร์หรือไม่? หรือstd::is_constructibleว่ามันไม่สอดคล้องกันจริงๆ?


1
ดูเหมือนว่าบั๊ก GCC เสียงดังกราว 9 ภาพ00
Yksisarvinen

1
อีกอย่างที่คิดว่าฉันสังเกตเห็นเมื่อทำการคอมไพล์ที่เครื่องของฉันด้วย c ++ 17 g ++ 9.2.1 / g ++ - 10.0 และแทนที่ std :: is_constructible <... > :: value ด้วย is_constructible_v <... > นั่นคือผลลัพธ์เปลี่ยนเป็น 00
mutableVoid

1
@mutableVoid แน่นอน - และดูเหมือนว่า::valueเวอร์ชันนั้นสามารถเปลี่ยนผลลัพธ์ของผู้ที่มาก่อนหน้าได้เช่นกัน: godbolt.org/z/zCy5xU ยกเลิกการใส่เครื่องหมายบรรทัดที่คอมเม้นต์และทั้งหมดกลายเป็น 1: s ใน gcc
Ted Lyngmo

1
อีกวิธีในการแก้ไข: godbolt.org/z/EKaP3rดังนั้นโดยทั่วไปนี่คือข้อผิดพลาดบางอย่างของการประเมินผล
Marek R

2
@mutableVoid คุณไม่จำเป็นต้องสร้างอินสแตนซ์ของฟังก์ชันแม่แบบเพื่อให้เป็นจริง ในตัวอย่างนี้มันจะส่งคืนfalseแต่ถ้าเทมเพลตของฟังก์ชั่นนั้นไม่ใส่เครื่องหมายถูกก็จะส่งคืนtrue: godbolt.org/z/zqxdk2
Ted Lyngmo

คำตอบ:


3

std::is_constructibleควรกลับมาfalseในสถานการณ์นี้เพราะตัวสร้างไม่สามารถเข้าถึงได้

ดังที่ระบุไว้ข้างใต้คำถามพฤติกรรมที่อธิบายในคำถามนั้นเกิดจากข้อบกพร่องใน GCC / libstdc ++ ข้อผิดพลาดมีการรายงานที่นี่และตาม Bugzilla เกี่ยวข้องกับถ้าไม่ได้เกิดจากข้อผิดพลาดการควบคุมการเข้าถึงสำหรับการเรียนในฟังก์ชั่นแม่แบบที่ได้รับการแก้ไขในขณะที่ ความสัมพันธ์ระหว่างข้อผิดพลาดสองตัวนั้นมาจากความคิดเห็น Bugzilla ของ Jonathan Wakely ซึ่งดูเหมือนว่าจะตรวจพบการเชื่อมต่อระหว่างข้อผิดพลาดสองตัวแรก

สิ่งนี้ยังบอกเป็นนัยถึงความจริงที่ว่าพฤติกรรมของสถานการณ์นี้ใน GCC นั้นถูกต้องเมื่อลบตัวสร้างแทนที่จะทำให้เป็นแบบส่วนตัว:

class Class {
    Class() = delete;
};

ซึ่งพิมพ์ออกมา 0และ00ตามลำดับ นี่คือเอาต์พุตที่ถูกต้อง (ซึ่งclangรายงานอย่างถูกต้องในสถานการณ์ที่มีตัวสร้างส่วนตัวเช่นกัน)

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

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