Pergunta

Um recurso do C ++ é a capacidade de criar namespaces sem nome (anônimos), assim:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

Você poderia pensar que tal característica um seria inútil - desde que você não pode especificar o nome do espaço de nomes, é impossível o acesso qualquer coisa dentro de fora. Mas esses namespaces sem nome são acessíveis dentro do arquivo que está criado, como se você tivesse um usando-cláusula implícita a eles.

A minha pergunta é, por que ou quando isso seria preferível ao uso de funções estáticas? Ou eles são essencialmente duas maneiras de fazer exatamente a mesma coisa?

Foi útil?

Solução

O padrão C ++ lê na seção 7.3.1.1 namespaces Sem nome, parágrafo 2:

O uso da palavra-chave estática é obsoleta quando declarar objetos em um escopo namespace, o sem nome-namespace fornece uma alternativa superior.

estática só se aplica aos nomes de objetos, funções e uniões anônimos, não digite declarações.

Editar:

A decisão de depreciar esse uso da palavra-chave estática (afetam a visibilidade de uma declaração de variável em uma unidade de tradução) foi invertida ( ref ). Neste caso, usando um estático ou um namespace sem nome estão de volta a ser essencialmente duas maneiras de fazer exatamente a mesma coisa. Para mais discussão consulte esta pergunta SO .

namespaces Sem nome ainda tem a vantagem de permitir a definição de tipos-tradução-unidade local. Por favor, consulte esta pergunta SO para mais detalhes.

O crédito vai para Mike Percy para trazer esse assunto a minha atenção.

Outras dicas

métodos Colocar em um anônimos impede de namespace que você acidentalmente violando a Uma regra Definição , permitindo-lhe nunca se preocupar com nomear seus métodos auxiliares o mesmo que algum outro método que você pode ligar em.

E, como apontado por luke, namespaces anônimos são preferidos pelo padrão sobre os membros estáticos.

Não é um caso extremo, onde estático tem um efeito surpreendente (pelo menos era para mim). O C ++ 03 estados padrão em 14.6.4.2/1:

Para uma chamada de função que depende de um parâmetro de modelo, se o nome da função é uma não qualificado-id , mas não um template-id , as funções candidatos são encontrados usando as regras de pesquisa habituais (3.4.1, 3.4.2), exceto que:

  • Para a parte da pesquisa utilizando a pesquisa de nome não qualificado (3.4.1), apenas declarações de função com ligação externa a partir do contexto de definição de molde são encontrados.
  • Para a parte da pesquisa utilizando espaços de nomes associados (3.4.2), apenas declarações de função com ligação externa encontrado tanto no âmbito de definição de modelo ou as contexto modelo instanciação são encontrados.

...

O código abaixo irá chamar foo(void*) e não foo(S const &) como você poderia esperar.

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

Em si, isso provavelmente não é esse negócio um grande, mas destaca que, para um compatível com C ++ compilador (ou seja, uma com suporte para export) totalmente a palavra-chave static ainda terá funcionalidade que não está disponível em qualquer outra forma.

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

A única maneira de garantir que a função em nosso namespace sem nome não será encontrado em modelos usando ADL é torná-lo static.

Atualização para Modern C ++

a partir de C ++ '11, membros de um espaço de nomes sem nome tem ligação interna implicitamente (3,5 / 4):

Um namespace sem nome ou um namespace declarou direta ou indiretamente dentro de um namespace sem nome tem ligação interna.

Mas, ao mesmo tempo, 14.6.4.2/1 foi atualizado para remover menção de ligação (esta tirada de C ++ '14):

Para uma chamada de função, onde o postfix-expressão é um nome dependente, as funções candidatos são encontrados usando as regras de pesquisa habituais (3.4.1, 3.4.2), exceto que:

  • Para a parte da pesquisa utilizando a pesquisa de nome não qualificado (3.4.1), apenas declarações de função a partir do contexto de definição de molde são encontrados.

  • Para a parte da pesquisa utilizando espaços de nomes associados (3.4.2), apenas a função declarações encontrado tanto no âmbito de definição de modelo ou as contexto modelo instanciação são encontrados.

O resultado é que essa diferença particular entre estática e membros namespace sem nome não existe mais.

Recentemente, começaram a substituir palavras-chave estáticas com namespaces anônimos em meu código, mas imediatamente correu para um problema onde as variáveis ??no espaço de nomes não estavam mais disponíveis para consulta no meu depurador. Eu estava usando VC60, então eu não sei se isso é um não-problema com outros depuradores. Minha solução foi definir um 'módulo' namespace, onde eu dei-lhe o nome do meu arquivo cpp.

Por exemplo, no meu arquivo XmlUtil.cpp, eu definir uma XmlUtil_I namespace {...} para todos os meus variáveis ??e funções do módulo. Dessa forma eu posso aplicar o XmlUtil_I :: qualificação no depurador para acessar as variáveis. Neste caso, distingue o '_I' lo de um namespace público, como XmlUtil que eu pode querer usar em outro lugar.

Eu suponho que uma desvantagem potencial desta abordagem em comparação com um verdadeiramente anônimo é que alguém poderia violar o alcance estático desejado usando o qualificador de namespace em outros módulos. Eu não sei se isso é uma grande preocupação embora.

O uso de palavra-chave estática para esse fim está obsoleta pelo padrão C ++ 98. O problema com estática é que ele não se aplica ao tipo definição. É também uma palavra-chave sobrecarregado usados ??de formas diferentes em contextos diferentes, assim namespaces anônimos simplificar as coisas um pouco.

A partir da experiência eu vou apenas observar que, embora seja o C ++ maneira de colocar funções anteriormente-estáticos para o namespace anônimo, compiladores mais velhos às vezes pode ter problemas com isso. Actualmente, eu trabalho com alguns compiladores para nossas plataformas de destino, e o compilador Linux mais moderno é muito bem com a colocação de funções no namespace anônimo.

Mas um compilador mais antigo em execução no Solaris, que estamos a casar com até um lançamento futuro não especificado, por vezes, irá aceitá-la, e outras vezes marcá-lo como um erro. O erro não é o que me preocupa, é o que pode fazer quando se aceita -lo. Então, até que nós vamos moderna através da placa, ainda estamos usando estática funções (geralmente de classe com escopo) em que preferiria o namespace anônimo.

Além disso, se um usa palavra-chave estática em uma variável como este exemplo:

namespace {
   static int flag;
}

Ele não iria ser visto no arquivo de mapeamento

Tendo aprendido deste recurso só agora ao ler sua pergunta, só posso especular. Isto parece oferecer diversas vantagens sobre uma variável de nível de arquivo estático:

  • namespaces anônimos podem ser aninhadas uma dentro da outra, oferecendo vários níveis de proteção contra os símbolos que não podem escapar.
  • Vários namespaces anônimos poderia ser colocado no mesmo arquivo de origem, criando efeito de nível estático escopos diferentes dentro do mesmo arquivo.

Eu estaria interessado em saber se alguém tem usado namespaces anônimos em código real.

A diferença compilador específico entre namespaces anônimos e funções estáticas pode ser visto compilar o código a seguir.

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

Compilar este código com o VS 2017 (especificando a bandeira de alerta nível 4 / W4 para permitir aviso C4505: função local não referenciado foi removido ) e gcc 4,9 com a função -Wunused ou mostra o sinalizador -Parede que VS 2017 só elabora um aviso para a função estática não utilizado. gcc 4.9 e superior, bem como clang 3.3 e superior, irá produzir avisos para a função unreferenced no espaço de nomes e também um aviso para a função estática não utilizado.

demonstração ao vivo do gcc 4.9 e MSVC 2017

Pessoalmente eu prefiro funções estáticas mais namespaces anônimos, pelas seguintes razões:

  • é óbvio e claro de definição de função por si só que é privada para a unidade de tradução em que ele é compilado. Com namespace namesless pode ser necessário percorrer e pesquisar para ver se uma função está em um namespace.

  • funções em namespaces pode ser tratado como externo por alguns compiladores (mais velhos). No VS2017 eles ainda são externa. Por esta razão, mesmo se a função está em namespace sem nome você ainda pode querer marcá-los estático.

  • funções estáticas comportar muito semelhante em C ou C ++, enquanto namespaces anônimos são, obviamente, C ++ somente. namespaces anônimos também adicionar nível extra se recuo e eu não gosto disso:)

Então, eu estou feliz de ver que o uso de estática para funções não está mais obsoleto.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top