คำถามติดแท็ก language-lawyer

สำหรับคำถามเกี่ยวกับความซับซ้อนของข้อกำหนดอย่างเป็นทางการหรือมีสิทธิ์ของภาษาโปรแกรมและสภาพแวดล้อม

1
ชั้นไม่สามารถเข้าถึงวิธี constexpr คงที่ส่วนตัวของตัวเอง - ข้อผิดพลาดดังกราว?
รหัสนี้ไม่ได้รวบรวมใน Clang (6,7,8,9 ลำตัว) แต่รวบรวมได้ใน GCC (7.1, 8.1, 9.1): template<class T> struct TypeHolder { using type = T; }; template<int i> class Outer { private: template<class T> static constexpr auto compute_type() { if constexpr (i == 42) { return TypeHolder<bool>{}; } else { return TypeHolder<T>{}; } } public: template<class T> …

2
การเพิ่มประสิทธิภาพที่ไม่คาดคิดของ strlen เมื่อสร้างสมนามอาร์เรย์ 2 มิติ
นี่คือรหัสของฉัน: #include <string.h> #include <stdio.h> typedef char BUF[8]; typedef struct { BUF b[23]; } S; S s; int main() { int n; memcpy(&s, "1234567812345678", 17); n = strlen((char *)&s.b) / sizeof(BUF); printf("%d\n", n); n = strlen((char *)&s) / sizeof(BUF); printf("%d\n", n); } ใช้ GCC 8.3.0 หรือ 8.2.1 ที่มีระดับการเพิ่มประสิทธิภาพใด ๆ ยกเว้น-O0ผลผลิตนี้เมื่อผมคาดหวังว่า0 …

3
เหตุใดจึงเลือกตัวดำเนินการแปลงเกินพิกัดนี้
พิจารณารหัสต่อไปนี้ struct any { template <typename T> operator T &&() const; template <typename T> operator T &() const; }; int main() { int a = any{}; } ที่นี่ผู้ประกอบการแปลงที่สองถูกเลือกโดยความละเอียดเกินพิกัด ทำไม? เท่าที่ฉันเข้าใจผู้ประกอบการทั้งสองจะอนุมานoperator int &&() constและoperator int &() constตามลำดับ ทั้งสองอยู่ในชุดของฟังก์ชันที่ทำงานได้ การอ่านผ่าน [over.match.best] ไม่ได้ช่วยฉันหาสาเหตุว่าทำไมสิ่งหลังถึงดีกว่า เหตุใดฟังก์ชันหลังจึงดีกว่ารุ่นก่อน

3
มันโอเคที่จะส่งคืนค่าอาร์กิวเมนต์เริ่มต้นโดยการอ้างอิง const หรือไม่
มันโอเคที่จะส่งคืนค่าอาร์กิวเมนต์เริ่มต้นโดยการอ้างอิง const เช่นในตัวอย่างด้านล่าง: https://coliru.stacked-crooked.com/a/ff76e060a007723b #include <string> const std::string& foo(const std::string& s = std::string("")) { return s; } int main() { const std::string& s1 = foo(); std::string s2 = foo(); const std::string& s3 = foo("s"); std::string s4 = foo("s"); }

1
ความหมายของวัตถุที่ทับซ้อนกันใน C คืออะไร?
พิจารณาโครงสร้างต่อไปนี้: struct s { int a, b; }; โดยทั่วไป1 โครงสร้างนี้จะมีขนาด 8 และการจัดตำแหน่ง 4 จะเกิดอะไรขึ้นถ้าเราสร้างstruct sวัตถุสองชิ้น (แม่นยำยิ่งกว่านั้นเราเขียนลงในวัตถุสองหน่วยดังกล่าวที่จัดสรรแล้ว) โดยที่วัตถุที่สองซ้อนทับวัตถุแรก char *storage = malloc(3 * sizeof(struct s)); struct s *o1 = (struct s *)storage; // offset 0 struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4 // now, o2 …

3
คอมไพเลอร์ได้รับอนุญาตให้ระเหยสารในท้องถิ่นได้หรือไม่?
พิจารณารหัสง่าย ๆ นี้: void g(); void foo() { volatile bool x = false; if (x) g(); } https://godbolt.org/z/I2kBY7 คุณจะเห็นว่าค่าgccมิได้เพิ่มประสิทธิภาพการโทรมีศักยภาพในการclang gสิ่งนี้ถูกต้องในความเข้าใจของฉัน: เครื่องนามธรรมคือการสันนิษฐานว่าvolatileตัวแปรอาจเปลี่ยนแปลงได้ตลอดเวลา (เนื่องจากเป็นเช่นการแมปฮาร์ดแวร์) ดังนั้นการfalseเริ่มต้นการพับการifตรวจสอบอย่างต่อเนื่องจะผิด แต่ MSVC กำจัดการเรียกไปที่gทั้งหมด (ทำให้การอ่านและเขียนไปยังvolatileแม้ว่า!) พฤติกรรมนี้เป็นไปตามมาตรฐานหรือไม่ พื้นหลัง: ฉันใช้โครงสร้างชนิดนี้เป็นครั้งคราวเพื่อให้สามารถเปิด / ปิดการดีบักเอาต์พุตแบบทันที: คอมไพเลอร์ต้องอ่านค่าจากหน่วยความจำเสมอดังนั้นการเปลี่ยนตัวแปร / หน่วยความจำในระหว่างการดีบักควรปรับเปลี่ยนการควบคุมตามลำดับ . เอาท์พุท MSVC จะอ่านค่าใหม่ แต่ไม่สนใจมัน (น่าจะเป็นเพราะการพับและ / หรือการกำจัดรหัสที่ตายแล้ว) ซึ่งแน่นอนว่าเอาชนะความตั้งใจของฉันที่นี่ การแก้ไข: การกำจัดของการอ่านและการเขียนvolatileถูกกล่าวถึงที่นี่: มันอนุญาตให้คอมไพเลอร์เพื่อปรับให้เหมาะสมกับตัวแปรที่ระเหยได้หรือไม่? (ขอบคุณนาธาน!) ฉันคิดว่ามาตรฐานมีความชัดเจนอย่างมากที่ผู้อ่านและเขียนจะต้องเกิดขึ้น แต่การสนทนานั้นไม่ครอบคลุมว่าจะเป็นการถูกกฎหมายหรือไม่ที่คอมไพเลอร์จะใช้ผลลัพธ์ของการอ่านเพื่อการอนุญาตและการปรับให้เหมาะสมตามนั้น …

2
ความหมายแบบอินไลน์ในโมดูลอินเตอร์เฟส
พิจารณาไฟล์ส่วนหัว: class T { private: int const ID; public: explicit T(int const ID_) noexcept : ID(ID_) {} int GetID() const noexcept { return ID; } }; หรืออีกทางหนึ่ง: class T { private: int const ID; public: explicit T(int const ID_) noexcept; int GetID() const noexcept; }; inline T::T(int const ID_) noexcept …

3
C ++ 20 Concepts: ความเชี่ยวชาญเทมเพลตใดที่ได้รับเลือกเมื่ออาร์กิวเมนต์เทมเพลตนั้นมีคุณสมบัติเหมาะสมสำหรับหลายแนวคิด
ให้: #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; …

3
ความแตกต่างของพฤติกรรมของฟังก์ชั่นแลมบ์ดาที่จับได้ไม่แน่นอนจากการอ้างอิงถึงตัวแปรทั่วโลก
ฉันพบว่าผลลัพธ์นั้นแตกต่างกันในคอมไพเลอร์ถ้าฉันใช้แลมบ์ดาเพื่อจับการอ้างอิงไปยังตัวแปรทั่วโลกด้วยคำสำคัญที่ไม่แน่นอนและปรับเปลี่ยนค่าในฟังก์ชั่นแลมบ์ดา #include <stdio.h> #include <functional> int n = 100; std::function<int()> f() { int &m = n; return [m] () mutable -> int { m += 123; return m; }; } int main() { int x = n; int y = f()(); int z = n; printf("%d %d %d\n", x, y, …

1
การใช้ตัวแปรใน initializer ของตัวเอง
[basic.scope.pdecl] / 1ของร่างมาตรฐาน C ++ 20 มีตัวอย่าง (ไม่ใช่กฎเกณฑ์) ดังต่อไปนี้ในบันทึกย่อ (อ้างบางส่วนจากก่อนที่จะรวมคำขอดึง 3580ดูคำตอบสำหรับคำถามนี้): unsigned char x = x; [... ] x ถูกเตรียมใช้งานด้วยค่าของตัวเอง (ไม่ทราบแน่ชัด) สิ่งนี้มีพฤติกรรมที่ชัดเจนใน C ++ 20 หรือไม่ โดยทั่วไปการกำหนดค่าเริ่มต้นด้วยตนเองของแบบฟอร์มT x = x;จะมีพฤติกรรมที่ไม่ได้กำหนดโดยอาศัยคุณค่าของxการไม่ได้กำหนดค่าก่อนที่การเริ่มต้นจะเสร็จสมบูรณ์ การประเมินค่าที่ไม่ทราบแน่ชัดมักทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด ( [basic.indent] / 2 ) แต่มีข้อยกเว้นเฉพาะใน[basic.indent] /2.3ที่อนุญาตให้เริ่มต้นunsigned charตัวแปรโดยตรงจากค่า lvalue unsigned charด้วยค่าที่ไม่ทราบแน่ชัด ) นี้เพียงอย่างเดียวไม่ดังนั้นจึงไม่ก่อให้เกิดพฤติกรรมที่ไม่ได้กำหนด แต่จะประเภทอื่น ๆTที่ไม่ได้รับการรับรองรูปแบบตัวอักษรหรือแคบเช่นstd::byte int x = x;ข้อควรพิจารณาเหล่านี้มีผลใน …

3
deleter ของ shared_ptr ถูกเก็บไว้ในหน่วยความจำที่จัดสรรโดยตัวจัดสรรที่กำหนดเองหรือไม่
บอกว่าผมมีshared_ptrกับการจัดสรรที่กำหนดเองและ Deleter ที่กำหนดเอง ฉันไม่สามารถหาอะไรในมาตรฐานที่พูดถึงว่าควรเก็บ deleter ที่ไหน: ไม่ได้บอกว่าตัวจัดสรรแบบกำหนดเองจะถูกใช้สำหรับหน่วยความจำของ deleter และมันไม่ได้บอกว่ามันจะไม่เป็นเช่นนั้น สิ่งนี้ไม่ได้ระบุหรือฉันเพิ่งจะพลาดบางสิ่ง

2
การเป็นประเภท POD เทียบเท่ากับประเภทเลย์เอาต์มาตรฐานหรือไม่?
ใน C ++ 20 แนวคิดของ POD ถูกคัดค้านเนื่องจากเป็นลักษณะประกอบที่ไม่มีความหมายว่าเป็นเรื่องไร้สาระและมีรูปแบบมาตรฐาน อย่างไรก็ตามคำจำกัดความของ PODในร่าง C ++ 20 นั้นไม่ตรงกับ "ทั้งเรื่องธรรมดาและเลย์เอาต์มาตรฐาน" มันเป็นจริง: คลาส POD เป็นคลาสที่มีทั้งคลาสที่ไม่สำคัญและคลาสเลย์เอาต์มาตรฐานและไม่มีสมาชิกข้อมูลที่ไม่ใช่แบบคงที่ประเภทคลาสที่ไม่ใช่ POD (หรืออาร์เรย์ดังกล่าว) ประเภท POD เป็นประเภทสเกลาร์, คลาส POD, อาร์เรย์ของประเภทดังกล่าวหรือรุ่นที่ผ่านการรับรอง cv ของหนึ่งในประเภทเหล่านี้ กล่าวอีกนัยหนึ่งไม่เพียง แต่จะเป็นประเภท POD ทั้งรูปแบบไม่สำคัญและรูปแบบมาตรฐาน แต่ก็มีรูปแบบซ้ำ ๆ ข้อกำหนดแบบเรียกซ้ำซ้อนนี้ซ้ำซ้อนหรือไม่ กล่าวอีกนัยหนึ่งถ้าประเภทมีทั้งแบบธรรมดาและแบบเลย์เอาต์มันจะเป็นแบบไม่สำคัญและแบบมาตรฐานแบบซ้ำ ๆ โดยอัตโนมัติหรือไม่? หากคำตอบคือ "ไม่" ดังนั้นตัวอย่างของเลย์เอาต์มาตรฐานประเภทเล็ก ๆ น้อย ๆ ที่ไม่ได้เป็น POD คืออะไร

2
คุณสมบัติของตัวชี้ไปยังอาร์เรย์ความยาวเป็นศูนย์
พิจารณา int main() { auto a = new int[0]; delete[] a; // So there's no memory leak } ระหว่างการคัดลอกเริ่มต้นและการลบคุณได้รับอนุญาตให้อ่านตัวชี้ที่a + 1? นอกจากนี้ไม่อนุญาตให้มีภาษาคอมไพเลอร์ชุดaไปnullptr?

4
การแปลงโดยปริยายไม่ได้รับอนุญาตเมื่อส่งคืน
#include <optional> bool f() { std::optional<int> opt; return opt; } ไม่ได้รวบรวม: 'return': cannot convert from 'std::optional<int>' to 'bool' การอ้างอิงการให้คำปรึกษาฉันคิดว่าจะหาคำอธิบาย แต่ฉันอ่านมันควรจะโอเค การแปลงโดยนัยจะดำเนินการทุกครั้งที่มีการใช้นิพจน์ประเภท T1 บางประเภทในบริบทที่ไม่ยอมรับประเภทนั้น แต่ยอมรับประเภท T2 บางประเภท โดยเฉพาะอย่างยิ่ง: เมื่อนิพจน์ใช้เป็นอาร์กิวเมนต์เมื่อเรียกใช้ฟังก์ชันที่ประกาศด้วย T2 เป็นพารามิเตอร์ เมื่อนิพจน์ถูกใช้เป็นตัวถูกดำเนินการกับตัวดำเนินการที่คาดว่า T2 เมื่อเริ่มต้นวัตถุใหม่ประเภท T2 รวมถึงคำสั่ง return ในฟังก์ชั่นการคืนค่า T2 เมื่อการแสดงออกที่ใช้ในงบสวิทช์ (T2 เป็นประเภทที่สำคัญ); เมื่อนิพจน์ถูกใช้ในคำสั่ง if หรือลูป (T2 คือบูล)

1
ทำไม {} เนื่องจากอาร์กิวเมนต์ของฟังก์ชันไม่นำไปสู่ความกำกวม?
พิจารณารหัสนี้: #include <vector> #include <iostream> enum class A { X, Y }; struct Test { Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X) { std::cout << "vector overload" << std::endl; } Test(const std::vector<double>&, int, A = A::X) { std::cout << "int overload" << std::endl; } }; int main() { …

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