30 votes

Le type de retour de la déduction pour une classe de fonctions ami

Voici une petite expérience avec le type de retour de la déduction pour ami de classe de fonctions (à l'aide de Clang 3.4 SVN et g++ 4.8.1 avec std=c++1y dans les deux cas) qui n'est pas documentée dans le rapport de travail du papier

#include <iostream>

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R) 
    { 
        return L.a_ == R.a_; // a_ is of type int, so should return bool
    }
};

template<class T>
struct B
{
    int b_;
    friend auto operator==(B const& L, B const& R) 
    { 
        return L.b_ == R.b_; // b_ is of type int, so should return bool
    }
};

using BI = B<int>;

int main()
{
    std::cout << (A{1} == A{2}) << "\n";    // OK for Clang, ERROR for g++
    std::cout << (BI{1} == BI{2}) << "\n";  // ERROR for both Clang and g++
}

Exemple Vivant.

Question: est automatique type de retour de la déduction pour la classe de ami les fonctions prises en charge en C++14?

10voto

dyp Points 19641

À l'égard des autres réponses: Nous sommes traitant explicitement de n3638 ici, et comment il est intégré dans la récente projets de C++1y.

Je suis en utilisant 9514cc28 du comité de dépôt github, qui intègre certains (mineur) des corrections/modifications n3638 déjà.

n3638 permet explicitement:

struct A {
  auto f(); // forward declaration
};
auto A::f() { return 42; }

Et, comme on peut l'inférer à partir de [dcl.spec.auto], où cette fonction est spécifiée, même les éléments suivants seront juridiques:

struct A {
  auto f(); // forward declaration
};

A x;

auto A::f() { return 42; }

int main() { x.f(); }

(mais plus sur cela plus tard)

C'est fondamentalement différente de toute fuite-retour-type ou dépendantes à la recherche d'un nom, comme auto f(); est une déclaration préliminaire, semblable à de la struct A;. Il doit être rempli plus tard, avant de l'utiliser (avant le type de retour est requis).

De plus, les problèmes dans les OP sont liées à l'intérieur d'erreurs du compilateur. La récente clang++3.4 tronc 192325 Debug+Affirme l'échec de la construction de compiler comme une assertion échoue lors de l'analyse de la ligne, return L.b_ == R.b_;. Je n'ai pas vérifié avec une version récente de g++ à partir de maintenant.


Est le cas des OP exemple juridique wrt pour un n3638?

C'est un peu délicat de l'OMI. (Je suis toujours en se référant à 9514cc28 dans cette section.)

1. Où est-il autorisé à utiliser "auto"?

[dcl.spec.auto]

6 Un programme qui utilise auto ou decltype(auto) dans un contexte non explicitement autorisés dans cette section est mal formé.

2 L'espace réservé type peuvent apparaître avec une fonction de demande de déclaration dans le decl-spécificateur-seq, type spécificateur-seq, conversion en fonction de l'id, ou de fuite-de retour, dans un contexte où une telle déclaration est valide.

/5 définit également certains contextes, mais ils sont hors de propos ici.

Par conséquent, auto func() et auto operator@(..) sont généralement autorisés (ce qui suit à partir de la composition d'une déclaration de fonction en tant que T DT est de la forme decl-spécificateur-seq, et auto est un type spécificateur).


2. Est-il permis d'écrire " auto func();`, c'est à dire une déclaration qui n'est pas une définition?

[dcl.spec.auto]/1 dit

L' auto et decltype(auto) type de spécificateurs de désigner un espace réservé à un type qui sera remplacé plus tard, soit par déduction à partir d'un initialiseur ou par spécification explicite avec une fuite de retour.

et /2

Si la déclaration de type de retour de la fonction contient un espace réservé à un type, le type de retour de la fonction est déduite de l' return des déclarations dans le corps de la fonction, le cas échéant.

Bien qu'il n'est pas explicitement autoriser une déclaration telle que celle - auto f(); pour une fonction (qui est, une déclaration sans définition), il est clair à partir de n3638 et [dcl.spec.auto]/11 qu'il est destiné à être autorisé, et pas explicitement interdit.


3. Qu'en est ami de fonctions?

Jusqu'à présent, l'exemple

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R);
}

auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; }

doit être bien formé. La partie intéressante est maintenant la définition de l'ami de la fonction à l'intérieur de la définition de l' A, qui est

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R)
    { return L.a_ == R.a_; } // allowed?
}

À mon avis, c'est permis. Pour ce faire, je vais citer la recherche d'un nom. La recherche de nom à l'intérieur de la définition des fonctions définies dans un ami de la déclaration de la fonction suit la recherche par nom de membre de fonctions comme par [de base.de recherche.unqual]/9. /8 du même article spécifie non qualifiés de recherche pour les noms utilisés à l'intérieur de membres de la fonction des organes. L'une des façons un nom peut être déclaré pour être utilisé, c'est qu'il "doit être un membre de la classe X , ou être membre d'une classe de base de l' X (10.2)". Ceci permet de largement connu

struct X
{
    void foo() { m = 42; }
    int m;
};

Notez comment m n'est pas déclarée avant son utilisation en foo, mais c'est un membre de l' X.

À partir de cela, je conclus que, même

struct X
{
    auto foo() { return m; }
    int m;
}

est autorisée. C'est pris en charge par clang++3.4 tronc 192325. Recherche de nom nécessite d'interpréter cette fonction uniquement après l' struct a été terminé, pensez également à:

struct X
{
    auto foo() { return X(); }
    X() = delete;
};

De même, le corps de l'ami des fonctions définies à l'intérieur d'une classe ne peuvent être interprétées qu'une fois que la classe est terminée.


4. Que sur les modèles?

Plus précisément, qu'en friend auto some_function(B const& L) { return L.b_; }?

Tout d'abord, le injecté-classe nom- B est équivalent à B<T>, voir [temp.local]/1. Il se réfère au courant de l'instanciation ([temp.dep.type]/1).

L' id de l'expression- L.b_ se réfère à un membre de l'actuel de l'instanciation (/4). Il est également dépendante des membres de l'actuel instanciation -- c'est une addition faite après C++11, voir DR1471, et je ne sais pas quoi penser à ce sujet: [temp.dep.expr]/5 membres de cette id-expression n'est pas dépendant du type, et aussi loin que je vois [temp.dep.constexpr] ne veut pas dire que c'est la valeur-dépendante.

Si le nom en L.b_ n'était pas dépendante, la recherche d'un nom suivra les "habituels de la recherche du nom de" règles par [temp.nondep]. Le reste, ça va être fun (dépendant de recherche de nom n'est pas très bien indiqué), mais considérant que

template<class T>
struct A
{
    int foo() { return m; }
    int m;
};

est acceptée par la plupart des compilateurs ainsi, je pense que la version avec auto devrait être valide, trop.

Il y a aussi une section sur les amis de modèles dans [temp.ami], mais IMO il n'est pas jeter de la lumière sur la recherche de nom ici.


Voir aussi cette discussion dans le isocpp-forum.

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