Quais espaços de nome existem e quais são as regras?

9

Nota: esta questão é sobre name space, não namespace.

O padrão C ++ tem algumas referências a name space, mas não vejo a definição disso. Os padrões dizem que rótulos e macros estão em diferentes espaços de nome. Todas as outras referências name spaceestão na seção de compatibilidade com C / C ++, como esta ( rascunho atual ):

Essa é uma das poucas incompatibilidades entre C e C ++ que podem ser atribuídas à nova definição de espaço de nome C ++, na qual um nome pode ser declarado como um tipo e um não-tipo em um único escopo, fazendo com que o nome não-tipo oculte o nome do tipo e exigindo que as palavras-chave classe, estrutura, união ou enum sejam usadas para se referir ao nome do tipo. Essa nova definição de espaço de nome fornece conveniências notacionais importantes aos programadores de C ++ e ajuda a tornar o uso dos tipos definidos pelo usuário o mais semelhante possível ao uso de tipos fundamentais.

Qual é essa nova definição de espaço para nome ? Onde posso encontrá-lo no padrão? Quais são as regras exatas? As regras parecem ser mais complicadas do que "tipos não ocultos". Como, isso não compila:

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

Mas isso faz:

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

E isso também não compila:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding
geza
fonte
A visão prática é que um espaço para nome é uma classe singleton com membros públicos (subclasses). Por favor, não me linche :-)
peterh - Reinstala Monica
2
@ peterh-ReinstateMonica leu a pergunta (novamente)
YSC 17/03
FWIW, seu link está vinculado às seções relevantes: Subcláusula afetada: [class.name] [consulte também [dcl.typedef]] Você pode ver essas seções sobre como as regras funcionam.
NathanOliver 17/03
Há pelo menos dois espaços de nome: um para rótulos [stmt.label]/1e outro para macros [cpp]/8.
YSC 17/03
11
É um pouco interessante (para mim) que tanto a descrição quanto o exemplo mostrem o oposto do que a lógica menciona; um nome de tipo que oculta um nome que não é do tipo. Dado o status preliminar, espero que esse parágrafo mude.
molbdnilo 17/03

Respostas:

2

O nome do espaço termo pode ser mais bem estabelecido na norma ISO C; citando a ISO C11 :

6.2.3 Espaços de nomes dos identificadores

Se mais de uma declaração de um identificador específico estiver visível em qualquer ponto de uma unidade de tradução, o contexto sintático desambigua os usos que se referem a diferentes entidades. Portanto, existem espaços de nomes separados para várias categorias de identificadores, da seguinte maneira:

  • nomes de rótulos (sem ambiguidade pela sintaxe da declaração e uso do rótulo);
  • as tags de estruturas, uniões e enumerações (desambiguadas seguindo any32) das palavras-chave struct, union ou enum);
  • os membros de estruturas ou sindicatos; cada estrutura ou união possui um espaço de nome separado para seus membros (sem ambiguidade pelo tipo da expressão usada para acessar o membro por meio do operador. ou ->);
  • todos os outros identificadores, chamados identificadores comuns (declarados em declaradores comuns ou como constantes de enumeração).

A nova definição de espaço de nome do C ++ não é, de maneira alguma, recente no tempo e foi descrita em [diff.class] / 1 em sua forma atual desde a introdução do padrão ISO C ++ em 98 . Ele só é mencionado em qualquer extensão nos contextos para os quais difere da ISO C, conforme [diff.class] / 1, que é citado pelo OP.

Afaics, precisamos recorrer à ISO C11 / 6.2.3 e combiná-la com [diff.class] / 1 da norma ISO C ++ para obter uma descrição coesa e completa da (nova) definição de espaço de nome do C ++ , menos que flagelemos a ISO Padrão C ++ para, por exemplo, [basic.scope.hiding] , [class.name] / 2 , [stmt.label] / 1 , [cpp.replace] / 8 e assim por diante para ver como e onde se aplica.

[class.name] / 2

Uma declaração de classe introduz o nome da classe no escopo em que é declarada e oculta qualquer classe, variável, função ou outra declaração desse nome em um escopo anexo. [...]

[stmt.label] / 1

Os rótulos têm seu próprio espaço para nome e não interferem com outros identificadores [...]

[cpp.replace] / 1

[...] Existe um espaço para nomes de macro. [...]

dfri
fonte
1

Em C (6.2.3 Espaços de nomes dos identificadores), a noção de espaços de nomes é definida da seguinte maneira.

1 Se mais de uma declaração de um identificador específico estiver visível em qualquer ponto de uma unidade de tradução, o contexto sintático desambigua os usos que se referem a diferentes entidades. Portanto, existem espaços de nomes separados para várias categorias de identificadores, da seguinte maneira:

- nomes de rótulos (sem ambiguidade pela sintaxe da declaração e uso do rótulo);

- as tags de estruturas, uniões e enumerações (desambiguadas seguindo any32) das palavras-chave struct, union ou enum);

- membros de estruturas ou sindicatos; cada estrutura ou união possui um espaço de nome separado para seus membros (sem ambiguidade pelo tipo da expressão usada para acessar o membro por meio do operador. ou ->);

- todos os outros identificadores, chamados identificadores comuns (declarados em declaradores comuns ou como constantes de enumeração).

Por exemplo, um nome de tag de estrutura pode coincidir com um nome de função porque eles pertencem a diferentes espaços de nome. Quando você especifica uma estrutura com um nome de marca de estrutura quando precisa usar a palavra-chave struct. Por exemplo, essas declarações não entram em conflito.

struct s
{
    int s;
};

void s( void );

struct s s1;

Nesse trecho de código, o nome sdo tag da estrutura não entra em conflito com o nome da função, s porque o nome do tag deve ser especificado com a palavra-chave struct.

No C ++, você tem permissão para usar nomes de tags de estrutura sem a palavra-chave struct.

Por exemplo

struct s
{
    int s;
};

s s;

é um código correto. Nesta declaração

s s;

o nome do identificador declarado soculta o nome da estrutura. Então, se você escreverá, por exemplo

s s1;

o compilador emitirá um erro porque nesta declaração s é considerado como o nome do identificador declarado acima. Para resolver a ambiguidade, você precisa usar a palavra-chave struct

struct s
{
    int s;
};

s s;

struct s s1;

Isso é descrito na seguinte citação do C ++ 20 Standard (6.3.1 Regiões e escopos declarativos)

4 Dado um conjunto de declarações em uma única região declarativa, cada uma especificando o mesmo nome não qualificado,

(4.1) - todos devem se referir à mesma entidade, ou todos se referem a funções e modelos de funções; ou

(4.2) - exatamente uma declaração deve declarar um nome de classe ou nome de enumeração que não seja um nome typedef e as demais declarações devem se referir à mesma variável, membro de dados não estático ou enumerador, ou todas se referem a funções e modelos de função ; nesse caso, o nome da classe ou o nome da enumeração está oculto (6.3.10). [ Nota: Um nome de espaço para nome ou um nome de modelo de classe deve ser exclusivo em sua região declarativa (10.3.2, Cláusula 17). - nota final ]

Como você pode ver na citação, um nome de espaço para nome deve ser exclusivo em sua região declarativa. Então, essas declarações

struct Foo { };
namespace Foo { } 

estão incorretos.

Vlad de Moscou
fonte