web-dev-qa-db-fra.com

Un nom de classe complet jusqu'à la portée globale est-il jamais requis pour les définitions de fonction membre hors ligne?

This question m'a amené à me demander s'il est jamais utile/nécessaire de qualifier complètement les noms de classe (y compris l'opérateur de portée globale) dans une définition de fonction membre hors classe.

D'une part, je n'ai jamais vu cela se faire auparavant (et la syntaxe pour le faire correctement semble obscure). D'un autre côté, la recherche de nom C++ est très simple, il existe donc peut-être un cas de coin.

Question:

Y a-t-il jamais un cas où l'introduction d'une définition de fonction de membre hors classe par
ReturnType (::Fully::Qualified::Class::Name::MemberFunctionName)(...) { ... }
serait différent de
ReturnType Fully::Qualified::Class::Name::MemberFunctionName(...) { ... } (pas de portée globale :: préfixe)?

Notez que les définitions de fonction membre doivent être placées dans un espace de noms contenant la classe, donc this n'est pas un exemple valide.

14
Max Langhof

Une directive-utilisation peut rendre ambiguë Fully sans qualification.

namespace Foo {
    struct X {
    };
}

using namespace Foo;
struct X {
    void c();
};

void X::c() { } // ambiguous
void ::X::c() { } // OK
12
T.C.

C'est nécessaire si on est masochiste et qu'on aime écrire des trucs comme ça

namespace foo {
    namespace foo {
        struct bar {
            void baz();
        };
    }

   struct bar {
       void baz();
   };

   void foo::bar::baz() {
   }

   void (::foo::bar::baz)() {
   }
} 

On peut bien sûr écrire la deuxième surcharge comme foo::foo::bar::baz de portée mondiale, mais la question était de savoir si les deux déclarations pouvaient avoir un sens différent. Je ne recommanderais pas d'écrire un tel code.

Si une directive using est utilisée, il peut y avoir un code déroutant.

Considérez le programme démonstratif suivant

#include <iostream>
#include <string>

namespace N1
{
    struct A
    {
        void f() const;
    };      
}

using namespace N1;

void A::f() const { std::cout << "N1::f()\n"; }

struct A
{
    void f() const;
};

void ::A::f() const { std::cout << "::f()\n"; }

int main() 
{
    N1::A().f();
    ::A().f();

    return 0;
}

Donc, pour plus de lisibilité, ce nom qualifié

void ::A::f() const { std::cout << "::f()\n"; }

montre précisément où la fonction est déclarée.

2
Vlad from Moscow