มีช่องว่างชื่ออะไรบ้างและมีกฎเกณฑ์อะไรบ้าง?

หมายเหตุ: คำถามนี้เกี่ยวกับ name space ไม่ใช่ namespace

มาตรฐาน C++ มีการอ้างอิงถึง name space แต่ฉันไม่เห็นคำจำกัดความของสิ่งนี้ มาตรฐานระบุว่าป้ายกำกับและมาโครอยู่ในช่องว่างชื่อที่แตกต่างกัน การอ้างอิงอื่นๆ ทั้งหมดถึง name space อยู่ในส่วนความเข้ากันได้ของ C/C++ เช่นนี้ (current ฉบับร่าง):

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

คำจำกัดความของพื้นที่ชื่อใหม่นี้คืออะไร ฉันจะหามันได้ในมาตรฐานที่ไหน? กฎที่แน่นอนคืออะไร? กฎดูเหมือนจะซับซ้อนกว่า "ประเภทการซ่อนที่ไม่ใช่ประเภท" เช่นนี้ไม่ได้รวบรวม:

typedef int Foo; // Foo is a type
void Foo();      // not a type, but compile error, instead of hiding

แต่สิ่งนี้ทำ:

struct Foo { }; // Foo is a type as well
void Foo();     // This hides the type Foo. "struct Foo" refers to the type

และนี่ก็ไม่ได้คอมไพล์เช่นกัน:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding

person geza    schedule 17.03.2020    source แหล่งที่มา
comment
มุมมองเชิงปฏิบัติคือเนมสเปซเป็นคลาสเดี่ยวที่มีสมาชิกสาธารณะทั้งหมด (คลาสย่อย) โปรดอย่ารังแกฉันเลย :-)   -  person peterh    schedule 17.03.2020
comment
@ peterh-ReinstateMonica อ่านคำถาม (อีกครั้ง)   -  person YSC    schedule 17.03.2020
comment
FWIW ลิงก์ของคุณเชื่อมโยงไปยังส่วนที่เกี่ยวข้อง: ส่วนย่อยที่ได้รับผลกระทบ: [class.name] [ดูเพิ่มเติม [dcl.typedef]] คุณสามารถดูส่วนเหล่านั้นเกี่ยวกับวิธีการทำงานของกฎ   -  person NathanOliver    schedule 17.03.2020
comment
มีช่องว่างชื่ออย่างน้อยสองช่อง: ช่องหนึ่งสำหรับป้ายกำกับ [stmt.label]/1 และอีกช่องสำหรับมาโคร < a href="https://eel.is/c++draft/cpp#replace-8" rel="nofollow noreferrer">[cpp]/8.   -  person YSC    schedule 17.03.2020
comment
หนึ่งรายการสำหรับประเภท (แต่ name space ไม่ปรากฏเป็นคำต่อคำ): [class.name]/2.   -  person YSC    schedule 17.03.2020
comment
@YSC: ใช่ หากมีการกล่าวถึงพื้นที่ชื่ออื่นสำหรับสิ่งอื่น ๆ ฉันคงไม่ถามคำถามนี้ แต่มีเพียงสอง Hit สำหรับเนมสเปซ (บวกสี่รายการในส่วนความเข้ากันได้ของ C/C++) ดังนั้นคำถาม   -  person geza    schedule 17.03.2020
comment
นี่คือสาเหตุที่ฉันไม่ได้ใส่สิ่งนี้ไว้ในส่วนคำตอบ นี่ไม่ใช่คำตอบ   -  person YSC    schedule 17.03.2020
comment
@YSC: เอาล่ะ :)   -  person geza    schedule 17.03.2020
comment
มันค่อนข้างน่าสนใจ (สำหรับฉัน) ที่ทั้งคำอธิบายและตัวอย่างแสดงให้เห็นตรงกันข้ามกับสิ่งที่เหตุผลกล่าวถึง ชื่อประเภทที่ซ่อนชื่อที่ไม่ใช่ประเภท เมื่อพิจารณาถึงสถานะฉบับร่างแล้ว ฉันคาดว่าย่อหน้านั้นจะมีการเปลี่ยนแปลง   -  person molbdnilo    schedule 17.03.2020


คำตอบ (2)


คำว่า name space อาจเป็นที่ยอมรับมากกว่าในมาตรฐาน ISO C อ้างถึง ISO C11:

6.2.3 ช่องว่างชื่อของตัวระบุ

หากมองเห็นการประกาศตัวระบุเฉพาะมากกว่าหนึ่งรายการ ณ จุดใดๆ ในหน่วยการแปล บริบททางวากยสัมพันธ์จะแยกแยะการใช้ที่อ้างถึงเอนทิตีที่แตกต่างกัน ดังนั้นจึงมีช่องว่างชื่อแยกต่างหากสำหรับตัวระบุประเภทต่างๆ ดังนี้

  • ชื่อฉลาก (แยกความกำกวมตามไวยากรณ์ของการประกาศและการใช้ฉลาก)
  • แท็กของโครงสร้าง สหภาพแรงงาน และการแจงนับ (แยกความกำกวมตามใดๆ 32) ของคำหลัก โครงสร้าง สหภาพ หรือแจงนับ)
  • สมาชิกของโครงสร้างหรือสหภาพแรงงาน แต่ละโครงสร้างหรือสหภาพจะมีช่องว่างชื่อแยกต่างหากสำหรับสมาชิก (แยกความกำกวมตามประเภทของนิพจน์ที่ใช้ในการเข้าถึงสมาชิกผ่านทางตัวดำเนินการ . หรือ -›)
  • ตัวระบุอื่นๆ ทั้งหมด เรียกว่าตัวระบุสามัญ (ประกาศในประกาศสามัญหรือเป็นค่าคงที่การแจงนับ)

อย่างไรก็ตาม คำจำกัดความของเนมสเปซ ใหม่ ของ C++ นั้น ไม่ใช่ ล่าสุดทันเวลา แต่อย่างใด และได้รับการอธิบายไว้ใน [diff.class] /1 ในรูปแบบปัจจุบัน นับตั้งแต่ ISO การแนะนำ C++ Standard ในปี 1998 มีการกล่าวถึงในความยาวเท่าใดก็ได้ในบริบทที่แตกต่างจาก ISO C ตาม [diff.class]/1 ซึ่งอ้างโดย OP

Afaics เราจำเป็นต้องใช้ ISO C11/6.2.3 และรวมเข้ากับ [diff.class]/1 ของมาตรฐาน ISO C++ เพื่อให้คำอธิบายที่สมบูรณ์และเหนียวแน่นของคำจำกัดความของพื้นที่ชื่อ (ใหม่) ของ C++ เราไม่สนับสนุนมาตรฐาน ISO C++ เช่น [basic.scope.hiding], [class.name]/2, [stmt.label]/1, [cpp.replace]/8 และอื่นๆ เพื่อดูว่าจะนำไปใช้อย่างไรและที่ไหน

[class.name]/2

การประกาศคลาสจะแนะนำชื่อคลาสในขอบเขตที่มีการประกาศ และซ่อนคลาส ตัวแปร ฟังก์ชัน หรือการประกาศอื่น ๆ ของชื่อนั้นไว้ในขอบเขตที่ปิดล้อม [...]

[stmt.label]/1

[...] ป้ายกำกับมีพื้นที่ชื่อของตัวเองและไม่รบกวนตัวระบุอื่น ๆ [...]

[cpp.replace]/1

[...] มีพื้นที่ชื่อหนึ่งสำหรับชื่อแมโคร [...]

person dfrib    schedule 17.03.2020

ใน C (6.2.3 ช่องว่างชื่อของตัวระบุ) แนวคิดของช่องว่างชื่อถูกกำหนดด้วยวิธีต่อไปนี้

1 หากมองเห็นการประกาศตัวระบุเฉพาะมากกว่าหนึ่งรายการ ณ จุดใดๆ ในหน่วยการแปล บริบททางวากยสัมพันธ์จะแยกแยะการใช้ที่อ้างถึงเอนทิตีที่แตกต่างกัน ดังนั้นจึงมีช่องว่างชื่อแยกต่างหากสำหรับตัวระบุประเภทต่างๆ ดังนี้

— ชื่อฉลาก (แยกความกำกวมตามไวยากรณ์ของการประกาศและการใช้ฉลาก)

- แท็กของโครงสร้าง สหภาพแรงงาน และการแจงนับ (แยกความกำกวมตามรายการใดๆ 32) ของคีย์เวิร์ด struct สหภาพ หรือแจงนับ)

- สมาชิกของโครงสร้างหรือสหภาพแรงงาน แต่ละโครงสร้างหรือสหภาพจะมีช่องว่างชื่อแยกต่างหากสำหรับสมาชิก (แยกความกำกวมตามประเภทของนิพจน์ที่ใช้ในการเข้าถึงสมาชิกผ่านทางตัวดำเนินการ . หรือ ->)

— ตัวระบุอื่นๆ ทั้งหมด เรียกว่าตัวระบุสามัญ (ประกาศในประกาศสามัญหรือเป็นค่าคงที่การแจงนับ)

ตัวอย่างเช่นชื่อแท็กโครงสร้างสามารถตรงกับชื่อฟังก์ชันได้เนื่องจากเป็นของช่องว่างชื่อที่แตกต่างกัน เมื่อคุณระบุโครงสร้างด้วยชื่อแท็กโครงสร้าง เมื่อคุณต้องใช้คีย์เวิร์ด struct ตัวอย่างเช่น การประกาศเหล่านี้ไม่ขัดแย้งกัน

struct s
{
    int s;
};

void s( void );

struct s s1;

ในข้อมูลโค้ดนี้ ชื่อแท็ก s ของโครงสร้างไม่ขัดแย้งกับชื่อฟังก์ชัน s เนื่องจากชื่อแท็กจะต้องระบุด้วยคำหลัก struct

ในภาษา C++ คุณได้รับอนุญาตให้ใช้ชื่อแท็กโครงสร้างโดยไม่มีคีย์เวิร์ด struct

ตัวอย่างเช่น

struct s
{
    int s;
};

s s;

เป็นรหัสที่ถูกต้อง ในแถลงการณ์นี้

s s;

ชื่อของตัวระบุที่ประกาศ s จะซ่อนชื่อโครงสร้าง ดังนั้นถ้าอย่างนั้นคุณจะเขียนตัวอย่าง

s s1;

จากนั้นคอมไพเลอร์จะออกข้อผิดพลาดเนื่องจากในคำสั่งนี้ถือเป็นชื่อของตัวระบุที่ประกาศไว้ข้างต้น เพื่อแก้ไขความกำกวม คุณต้องใช้คีย์เวิร์ด struct

struct s
{
    int s;
};

s s;

struct s s1;

สิ่งนี้อธิบายไว้ในคำพูดต่อไปนี้จากมาตรฐาน C ++ 20 (6.3.1 ขอบเขตและขอบเขตการประกาศ)

4 ให้ชุดการประกาศในภูมิภาคประกาศเดียว ซึ่งแต่ละแห่งระบุชื่อเดียวกันอย่างไม่มีเงื่อนไข

(4.1) — ทั้งหมดจะอ้างถึงเอนทิตีเดียวกัน หรือทั้งหมดอ้างถึงฟังก์ชันและเทมเพลตฟังก์ชัน หรือ

(4.2) — การประกาศครั้งเดียวจะต้องประกาศชื่อคลาสหรือชื่อการแจกแจงที่ไม่ใช่ชื่อ typedef และการประกาศอื่น ๆ ทั้งหมดจะอ้างอิงถึงตัวแปรเดียวกัน สมาชิกข้อมูลที่ไม่คงที่ หรือตัวแจงนับ หรือทั้งหมดอ้างถึงฟังก์ชันและเทมเพลตฟังก์ชัน ; ในกรณีนี้ชื่อคลาสหรือชื่อการแจกแจงถูกซ่อนไว้ (6.3.10) [ หมายเหตุ: ชื่อเนมสเปซหรือชื่อเทมเพลตคลาสจะต้องไม่ซ้ำกันในภูมิภาคที่ประกาศ (10.3.2 ข้อ 17) — บันทึกท้าย ]

ดังที่คุณเห็นจากเครื่องหมายคำพูด ชื่อเนมสเปซจะต้องไม่ซ้ำกันในภูมิภาคที่ประกาศ ดังนั้นการประกาศเหล่านี้

struct Foo { };
namespace Foo { } 

ไม่ถูกต้อง

person Vlad from Moscow    schedule 17.03.2020