391 votes

À quoi servent les espaces de noms en ligne?

C++11 permet à l' inline namespaces, tous les membres sont également automatiquement dans la enfermant namespace. Je ne crois pas du tout utile à l'application du présent -- quelqu'un peut-il veuillez donner une brève et succincte exemple d'une situation où un inline namespace est nécessaire et où il est le plus idiomatique solution?

(De plus, il n'est pas clair pour moi ce qui se passe quand un namespace est déclarée inline dans l'un mais pas l'ensemble des déclarations, qui peuvent vivre dans des fichiers différents. N'est-ce pas la mendicité pour le mal?)

383voto

Marc Mutz - mmutz Points 10367

Inline espaces de noms sont une bibliothèque fonctionnalité de gestion des versions semblable à symbole de gestion des versions, mais la mise en œuvre purement le C++11 niveau (ie. multi-plateforme), au lieu d'être une caractéristique spécifique d'un fichier binaire exécutable format (ie. plate-forme spécifique).

C'est un mécanisme par lequel une bibliothèque d'auteur peuvent faire d'un espace de noms imbriqué regarder et agir comme si tous ses déclarations ont été dans les environs de l'espace de noms (inline espaces de noms peuvent être imbriquées, donc "plus imbriquée" noms s'infiltrer jusqu'à la première non en ligne de l'espace de noms et d'examiner et d'agir comme si leurs déclarations dans les espaces de noms entre les deux, trop).

Considérez, par exemple, la STL mise en œuvre de l' vector. Si nous avions inline espaces de noms à partir du début de C++, puis en C++98 l'en-tête <vector> pourrait ressembler à ceci:

namespace std {

#if __cplusplus < 1997L // pre-standard C++
    inline
#endif

    namespace pre_cxx_1997 {
        template <class T> __vector_impl; // implementation class
        template <class T> // e.g. w/o allocator argument
        class vector : __vector_impl<T> { // private inheritance
            // ...
        };
    }
#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)
#  if __cplusplus == 1997L // C++98/03
    inline
#  endif

    namespace cxx_1997 {

        // std::vector now has an allocator argument
        template <class T, class Alloc=std::allocator<T> >
        class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
            // ...
        };

        // and vector<bool> is special:
        template <class Alloc=std::allocator<bool> >
        class vector<bool> {
            // ...
        };

    };

#endif // C++98/03 or later

} // namespace std

Selon la valeur de __cplusplus, soit l'un ou l'autre vector mise en œuvre est choisi. Si votre base de code a été écrit en pré-C++98 fois, et que vous trouvez que le C++98 version de vector est à l'origine de la difficulté pour vous lorsque vous mettez à niveau votre compilateur, "tous", vous avez à faire est de trouver les références à std::vector dans votre base de code et de les remplacer par std::pre_cxx_1997::vector.

Venir la prochaine norme, et la STL vendeur ne fait que répéter la procédure de nouveau, l'introduction d'un nouvel espace de noms pour std::vector avec emplace_back de soutien (ce qui nécessite de C++11) et l'in-lining que l'on iff __cplusplus == 201103L.

OK, alors pourquoi ai-je besoin d'une nouvelle fonctionnalité pour cela? Je peux déjà faire ce qui suit pour avoir le même effet, non?

namespace std {

    namespace pre_cxx_1997 {
        // ...
    }
#if __cplusplus < 1997L // pre-standard C++
    using namespace pre_cxx_1997;
#endif

#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)

    namespace cxx_1997 {
        // ...
    };
#  if __cplusplus == 1997L // C++98/03
    using namespace cxx_1997;
#  endif

#endif // C++98/03 or later

} // namespace std

Selon la valeur de __cplusplus,- je obtenir soit l'un ou l'autre des implémentations.

Et vous auriez presque correct.

Considérez les points suivants valide en C++98 code de l'utilisateur (il a été autorisé à se spécialiser entièrement des modèles qui vivent dans l'espace de noms std en C++98, déjà):

// I don't trust my STL vendor to do this optimisation, so force these 
// specializations myself:
namespace std {
    template <>
    class vector<MyType> : my_special_vector<MyType> {
        // ...
    };
    template <>
    class vector<MyOtherType> : my_special_vector<MyOtherType> {
        // ...
    };
    // ...etc...
} // namespace std

C'est parfaitement valide code si l'utilisateur fournit son propre mise en œuvre d'un vecteur d'un ensemble de type où apparemment elle sait une application plus efficace que l'on retrouve dans (sa copie de la STL).

Mais: Quand spécialisée d'un modèle, vous devez le faire dans l'espace de noms, il a été déclaré dans. La Norme dit qu' vector est déclaré dans l'espace de noms std, de sorte que lorsque l'utilisateur s'attend légitimement à se spécialiser le type.

Ce code fonctionne avec un non versionnés espace de noms std, ou avec le C++11 inline fonctionnalité des espaces de noms, mais pas avec la gestion des versions truc qui utilisaient using namespace <nested>, parce que expose le détail de l'implémentation que la véritable espace de noms dans lequel vector a été défini n'a pas été std directement.

Il y a d'autres trous par lesquels vous pourriez détecter le sous-espace de noms (voir les commentaires ci-dessous), mais inline espaces de noms les brancher tous. Et c'est tout là est à lui. Très utiles pour l'avenir, mais autant que je sache, le Standard ne veut pas prescrire inline noms d'espaces de noms pour sa propre bibliothèque standard (j'aimerais avoir tort sur ce point, tout de même), de sorte qu'il peut être utilisé uniquement pour les bibliothèques de tiers, pas de la norme elle-même (à moins que les éditeurs de compilateurs d'accord sur un schéma de nommage).

84voto

Steve Jessop Points 166970

http://www.stroustrup.com/C++11FAQ.html#inline-espace de noms (un document écrit et maintenu par Bjarne Stroustrup, qui vous devriez penser devrait être au courant de la plupart des motivations pour la plupart C++11 caractéristiques.)

Selon cela, c'est de permettre le contrôle de version pour des raisons de compatibilité descendante. Vous définissez plusieurs intérieure des espaces de noms, et de le rendre le plus récent, en inline. Ou en tout cas, la valeur par défaut pour les gens qui ne se soucient pas de contrôle de version. Je suppose que la plus récente pourrait être un futur ou la pointe de la version qui n'est pas encore défaut.

L'exemple donné est:

// file V99.h:
inline namespace V99 {
    void f(int);    // does something better than the V98 version
    void f(double); // new feature
    // ...
}

// file V98.h:
namespace V98 {
    void f(int);    // does something
    // ...
}

// file Mine.h:
namespace Mine {
#include "V99.h"
#include "V98.h"
}

#include "Mine.h"
using namespace Mine;
// ...
V98::f(1);  // old version
V99::f(1);  // new version
f(1);       // default version

Je n'ai pas immédiatement voir pourquoi vous ne mettez pas de using namespace V99; à l'intérieur de l'espace de noms Mine, mais je n'ai pas tout à fait comprendre les cas d'utilisation afin de prendre Bjarne la parole que sur la motivation du comité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X