web-dev-qa-db-fra.com

Quel est le nom complet d'une fonction amie définie à l'intérieur d'une classe?

Quel est le nom complet d'une fonction amie définie à l'intérieur d'une classe?

J'ai récemment vu un exemple analogue au suivant. Quel est le nom complet de val() ci-dessous?

#include <iostream>

namespace foo {
    class A {
        int x;
    public:
        A(int x = 0) : x(x) { }

        friend int val(const A &a) { return a.x; }
    };
}

int main() {
    foo::A a(42);

    // val() found using ADL:
    std::cout << val(a) << std::endl;

    // foo::val(a); // error: 'val' is not a member of 'foo'
    // foo::A::val(a); // error: 'val' is not a member of 'foo::A'

    return 0;   
}

La recherche dépendante de l'argument est-elle le seul moyen de trouver val()?

Certes, cela ne découle pas d'un problème pratique. Je cherche simplement à mieux comprendre.

46
Szabolcs

La recherche dépendante de l'argument est-elle le seul moyen de trouver val ()?

Oui, c'est le seul moyen. Pour citer la norme sacrée à [namespace.memdef]/ :

Si une déclaration friend dans une classe non locale déclare d'abord une classe, une fonction, un modèle de classe ou un modèle de fonction, l'ami est membre de l'espace de noms englobant le plus interne. La déclaration d'amis ne rend pas en elle-même le nom visible pour la recherche non qualifiée ou la recherche qualifiée.

Ainsi, alors que val est membre de foo, il n'est pas visible de rechercher à partir de la seule déclaration friend. Une définition hors classe (qui est également une déclaration) est requise pour la rendre visible. Pour une définition en ligne (et pas de déclaration hors classe), cela signifie qu'ADL est le seul moyen d'appeler la fonction.


En prime, C++ avait une fois un concept d '"injection de nom d'ami". Cependant, cela a été supprimé et les règles pour ADL ont été modifiées en remplacement. Un aperçu plus détaillé peut être trouvé dans le document WG21 N0777 (pdf).

36
StoryTeller

Norme C++ [7.3.1.2/3 (de l'ISO/CEI 14882: 2011)]:

Chaque nom déclaré pour la première fois dans un espace de noms est membre de cet espace de noms. Si une déclaration friend dans une classe non locale déclare d'abord une classe ou une fonction, la classe ou la fonction friend est membre de l'espace de noms englobant le plus intérieur.Le nom de l'ami n'est pas trouvé par recherche non qualifiée (3.4.1) ou par recherche qualifiée (3.4.3) jusqu'à ce qu'une déclaration correspondante soit fournie dans la portée de cet espace de noms (avant ou après la définition de classe accordant l'amitié). Si une fonction amie est appelée, son nom peut être trouvé par la recherche de nom qui prend en compte les fonctions des espaces de noms et des classes associées aux types des arguments de fonction (3.4.2). Si le nom dans une déclaration d'ami n'est ni qualifié ni un identifiant de modèle et que la déclaration est une fonction ou un spécificateur de type élaboré, la recherche pour déterminer si l'entité a déjà été déclarée ne doit pas prendre en compte les étendues extérieures l'espace de noms le plus à l'intérieur.

7
msc