Portanto, para resumir os pontos principais, using namespace v99
e inline namespace
não eram os mesmos, o primeiro era uma solução alternativa para as bibliotecas de versões antes de uma palavra-chave dedicada (inline) ser introduzida no C ++ 11, que corrigia os problemas de uso using
e fornecia a mesma funcionalidade de versão. O uso de using namespace
usado para causar problemas com o ADL (embora o ADL agora pareça seguir as using
diretrizes) e a especialização fora de linha de uma classe / função da biblioteca etc. pelo usuário não funcionariam se fossem feitas fora do namespace verdadeiro (cujo nome o o usuário não saberia e não deveria saber, ou seja, o usuário teria que usar B :: abi_v2 :: em vez de apenas B :: para a especialização resolver).
//library code
namespace B { //library name the user knows
namespace A { //ABI version the user doesn't know about
template<class T> class myclass{int a;};
}
using namespace A; //pre inline-namespace versioning trick
}
// user code
namespace B { //user thinks the library uses this namespace
template<> class myclass<int> {};
}
Isso mostrará um aviso de análise estática first declaration of class template specialization of 'myclass' outside namespace 'A' is a C++11 extension [-Wc++11-extensions]
. Mas se você criar o espaço para nome A embutido, o compilador resolverá corretamente a especialização. Embora, com as extensões do C ++ 11, o problema desapareça.
Definições fora de linha não resolvem ao usar using
; eles precisam ser declarados em um bloco de namespace de extensão aninhada / não aninhada (o que significa que o usuário precisa conhecer a versão ABI novamente, se por qualquer motivo, tiver permissão para fornecer sua própria implementação de uma função).
#include <iostream>
namespace A {
namespace B{
int a;
int func(int a);
template<class T> class myclass{int a;};
class C;
extern int d;
}
using namespace B;
}
int A::d = 3; //No member named 'd' in namespace A
class A::C {int a;}; //no class named 'C' in namespace 'A'
template<> class A::myclass<int> {}; // works; specialisation is not an out-of-line definition of a declaration
int A::func(int a){return a;}; //out-of-line definition of 'func' does not match any declaration in namespace 'A'
namespace A { int func(int a){return a;};} //works
int main() {
A::a =1; // works; not an out-of-line definition
}
O problema desaparece ao criar o B inline.
Os outros inline
namespaces de funcionalidade possuem permitem que o gravador da biblioteca forneça uma atualização transparente para a biblioteca 1) sem forçar o usuário a refatorar o código com o novo nome do namespace e 2) evitando falta de verbosidade e 3) fornecendo abstração de detalhes irrelevantes da API, enquanto 4) fornecer o mesmo diagnóstico e comportamento benéfico do vinculador que o uso de um espaço para nome não embutido forneceria. Digamos que você esteja usando uma biblioteca:
namespace library {
inline namespace abi_v1 {
class foo {
}
}
}
Ele permite que o usuário ligue library::foo
sem precisar saber ou incluir a versão ABI na documentação, que parece mais limpa. Usar library::abiverison129389123::foo
pareceria sujo.
Quando uma atualização é feita para foo
, ou seja, adicionar um novo membro à classe, ela não afeta os programas existentes no nível da API, porque eles ainda não estão usando o membro E a alteração no nome do namespace embutido não altera nada no nível da API. porque library::foo
ainda vai funcionar.
namespace library {
inline namespace abi_v2 {
class foo {
//new member
}
}
}
No entanto, para programas vinculados a ele, porque o nome do espaço para nome embutido é dividido em nomes de símbolo como um espaço para nome regular, a alteração não será transparente para o vinculador. Portanto, se o aplicativo não for recompilado, mas estiver vinculado a uma nova versão da biblioteca, ele apresentará um abi_v1
erro de erro não encontrado, em vez de vincular e causar um erro lógico misterioso no tempo de execução devido à incompatibilidade ABI. A adição de um novo membro causará compatibilidade com a ABI devido à alteração na definição de tipo, mesmo que não afete o programa no momento da compilação (nível da API).
Neste cenário:
namespace library {
namespace abi_v1 {
class foo {
}
}
inline namespace abi_v2 {
class foo {
//new member
}
}
}
Assim como o uso de dois namespaces não embutidos, ele permite que uma nova versão da biblioteca seja vinculada sem a necessidade de recompilar o aplicativo, porque abi_v1
será confundida com um dos símbolos globais e usará a definição de tipo correta (antiga). No entanto, recompilar o aplicativo faria com que as referências fossem resolvidas library::abi_v2
.
Usar using namespace
é menos funcional do que usar inline
(pois as definições fora de linha não resolvem), mas oferece as mesmas 4 vantagens acima. Mas a verdadeira questão é: por que continuar usando uma solução alternativa quando agora existe uma palavra-chave dedicada para fazer isso? É uma prática melhor, menos detalhada (precisa alterar uma linha de código em vez de 2) e torna clara a intenção.
using namespace V99;
que não funciona no exemplo de Stroustrup.