Apa ruang nama yang ada dan aturannya?

9

Catatan: pertanyaan ini tentang name space, bukan namespace.

Standar C ++ memiliki beberapa referensi name space, tetapi saya tidak melihat definisi ini. Standar mengatakan bahwa label dan makro berada dalam ruang nama yang berbeda. Semua referensi lain name spaceada di bagian kompatibilitas C / C ++, seperti ini ( konsep saat ini ):

Ini adalah salah satu dari beberapa ketidakcocokan antara C dan C ++ yang dapat dikaitkan dengan definisi ruang nama C ++ baru di mana nama dapat dideklarasikan sebagai tipe dan sebagai non-tipe dalam lingkup tunggal yang menyebabkan nama non-tipe menyembunyikan ketik nama dan mensyaratkan bahwa kelas kata kunci, struct, union atau enum digunakan untuk merujuk pada nama tipe. Definisi ruang nama baru ini memberikan kemudahan notasi penting bagi pemrogram C ++ dan membantu membuat penggunaan tipe-tipe yang didefinisikan pengguna semirip mungkin dengan penggunaan tipe fundamental.

Apa definisi ruang nama baru ini ? Di mana saya bisa menemukannya di standar? Apa aturannya? Aturan tampaknya lebih rumit, daripada "tipe non-tipe hide". Seperti, ini tidak mengkompilasi:

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

Tapi ini memang:

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

Dan ini tidak dapat dikompilasi:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding
geza
sumber
Pandangan praktisnya adalah bahwa namespace adalah kelas tunggal dengan semua anggota publik (subclass). Tolong jangan lynch saya :-)
peterh - Reinstate Monica
2
@ peterh-ReinstateMonica membaca pertanyaan (lagi)
YSC
FWIW, tautan Anda terhubung ke bagian yang relevan: Subclause yang terpengaruh: [class.name] [lihat juga [dcl.typedef]] Anda dapat melihat bagian-bagian itu untuk mengetahui bagaimana aturan itu bekerja.
NathanOliver
Setidaknya ada dua ruang nama: satu untuk label [stmt.label]/1dan satu untuk makro [cpp]/8.
YSC
1
Agak menarik (bagi saya) bahwa deskripsi dan contohnya menunjukkan kebalikan dari apa yang disebut alasannya; nama tipe menyembunyikan nama non-tipe. Mengingat status konsep, saya berharap paragraf itu berubah.
molbdnilo

Jawaban:

2

The ruang nama jangka mungkin lebih mapan di C Standar ISO; mengutip ISO C11 :

6.2.3 Beri nama ruang pengidentifikasi

Jika lebih dari satu deklarasi pengenal tertentu terlihat di setiap titik di unit terjemahan, konteks sintaksis melucuti penggunaan yang merujuk pada entitas yang berbeda. Dengan demikian, ada ruang nama terpisah untuk berbagai kategori pengidentifikasi, sebagai berikut:

  • nama label (disatukan dengan sintaks deklarasi dan penggunaan label);
  • tag struktur, serikat pekerja, dan enumerasi (disatukan dengan mengikuti32) dari kata kunci struct, union, atau enum);
  • anggota struktur atau serikat pekerja; setiap struktur atau gabungan memiliki ruang nama terpisah untuk anggotanya (disatukan dengan jenis ungkapan yang digunakan untuk mengakses anggota melalui operator. atau ->);
  • semua pengidentifikasi lainnya, disebut pengidentifikasi biasa (dideklarasikan dalam deklarator biasa atau sebagai konstanta enumerasi).

Namun definisi ruang nama baru dari C ++, sama sekali tidak baru-baru ini , dan telah dijelaskan dalam [diff.class] / 1 dalam bentuknya saat ini sejak diperkenalkannya standar ISO C ++ di tahun '98 . Ini hanya pernah disebutkan dalam konteks apa pun yang berbeda dari ISO C, sesuai [diff.class] / 1 yang dikutip oleh OP.

Afaics kita perlu menggunakan ISO C11 / 6.2.3 dan menggabungkannya dengan [diff.class] / 1 dari ISO C ++ Standard untuk deskripsi yang kohesif dan lengkap tentang definisi ruang nama C ++ yang baru , lebih sedikit kita mencari ISO C ++ Standar untuk misalnya [basic.scope.hiding] , [class.name] / 2 , [stmt.label] / 1 , [cpp.replace] / 8 dan seterusnya untuk melihat bagaimana dan di mana itu berlaku.

[class.name] / 2

Deklarasi kelas memperkenalkan nama kelas ke dalam ruang lingkup di mana ia dideklarasikan dan menyembunyikan kelas, variabel, fungsi, atau deklarasi lain dari nama itu dalam lingkup terlampir. [...]

[stmt.label] / 1

[...] Label memiliki ruang namanya sendiri dan tidak mengganggu pengidentifikasi lainnya [...]

[cpp.replace] / 1

[...] Ada satu ruang nama untuk nama makro. [...]

dfri
sumber
1

Dalam C (6.2.3 Ruang nama pengidentifikasi) pengertian ruang nama didefinisikan dengan cara berikut.

1 Jika lebih dari satu deklarasi pengenal tertentu terlihat di setiap titik dalam unit terjemahan, konteks sintaksis melucuti penggunaan yang merujuk pada entitas yang berbeda. Dengan demikian, ada ruang nama terpisah untuk berbagai kategori pengidentifikasi, sebagai berikut:

- nama label (disatukan oleh sintaks deklarasi dan penggunaan label);

- tag struktur, serikat pekerja, dan enumerasi (disatukan dengan mengikuti32) dari kata kunci struct, union, atau enum);

- anggota struktur atau serikat pekerja; setiap struktur atau gabungan memiliki ruang nama terpisah untuk anggotanya (disatukan dengan jenis ungkapan yang digunakan untuk mengakses anggota melalui operator. atau ->);

- semua pengidentifikasi lainnya, disebut pengidentifikasi biasa (dideklarasikan dalam deklarator biasa atau sebagai konstanta enumerasi).

Jadi misalnya nama tag struktur dapat bertepatan dengan nama fungsi karena mereka milik ruang nama yang berbeda. Ketika Anda menentukan struktur dengan nama tag struktur ketika Anda harus menggunakan kata kunci struct. Jadi misalnya deklarasi ini tidak bertentangan.

struct s
{
    int s;
};

void s( void );

struct s s1;

Dalam cuplikan kode ini nama tag sstruktur tidak bertentangan dengan nama fungsi s karena nama tag harus ditentukan dengan kata kunci struct.

Di C ++ Anda diizinkan menggunakan nama tag struktur tanpa kata kunci struct.

Sebagai contoh

struct s
{
    int s;
};

s s;

adalah kode yang benar. Dalam deklarasi ini

s s;

nama pengidentifikasi yang dinyatakan smenyembunyikan nama struktur. JADI kalau begitu Anda akan menulis misalnya

s s1;

maka kompiler akan mengeluarkan kesalahan karena dalam pernyataan ini s dianggap sebagai nama pengidentifikasi yang dinyatakan di atas. Untuk menyelesaikan ambiguitas, Anda perlu menggunakan kata kunci struct

struct s
{
    int s;
};

s s;

struct s s1;

Ini dijelaskan dalam kutipan berikut dari Standar C ++ 20 (6.3.1 Wilayah dan cakupan deklaratif)

4 Diberikan seperangkat deklarasi dalam satu wilayah deklaratif, yang masing-masing menentukan nama yang tidak memenuhi syarat yang sama,

(4.1) - mereka semua akan merujuk pada entitas yang sama, atau semua merujuk pada fungsi dan templat fungsi; atau

(4.2) - tepat satu deklarasi akan mendeklarasikan nama kelas atau nama enumerasi yang bukan nama typedef dan deklarasi lainnya semuanya akan merujuk ke variabel yang sama, anggota data non-statis, atau enumerator, atau semua merujuk pada fungsi dan templat fungsi ; dalam hal ini nama kelas atau nama enumerasi disembunyikan (6.3.10). [ Catatan: Nama namespace atau nama templat kelas harus unik di wilayah deklaratifnya (10.3.2, Klausa 17). - catatan akhir ]

Seperti yang Anda lihat dari kutipan, nama namespace harus unik di wilayah deklaratifnya. Jadi deklarasi ini

struct Foo { };
namespace Foo { } 

salah

Vlad dari Moskow
sumber