28 votes

Résolution de surcharge et tableaux: quelle fonction appeler?

Considérons le programme suivant:

#include <cstddef>
#include <cstdio>

void f(char const*&&)      { std::puts("char const*&&");      } // (1)
void f(char const* const&) { std::puts("char const* const&"); } // (2)

template <std::size_t N>
void f(char const (&)[N])  { std::puts("char const(&)[N]");   } // (3)

int main()
{
    const char data[] = "a";
    f(data);
}

Qui f devrait être appelé? Pourquoi?

La toute dernière version de trois compilateurs sont en désaccord sur la réponse à cette question:

  • (1) est appelée lorsque le programme est compilé à l'aide de g++ 4.5.2
  • (2) est appelée lorsque le programme est compilé à l'aide de Visual C++ 2010 SP1
  • (3) est appelée lorsque le programme est compilé à l'aide de Clang 3.0 (tronc 127530)

Avoir la résolution de surcharge règles changé radicalement différent de C++0x brouillons? Ou, sont deux de ces compilateurs vraiment juste complètement faux? Qui surcharge est la bonne surcharge d'être sélectionné par le dernier C++0x projet?

12voto

Johannes Schaub - litb Points 256113

Tout d'abord, la conversion de la séquence de tous les trois est la même, sauf que pour les deux premiers, il y a une lvalue transformation (lvalue à rvalue de conversion), qui n'est cependant pas utilisé dans la commande de conversion de séquences. Tous les trois sont des correspondances exactes (le modèle de fonction de la spécialisation a type de paramètre char const(&)[2]).

Si vous parcourez les règles de l' 13.3.3.2p3, vous vous arrêtez à ce paragraphe

S1 et S2 sont référence des liaisons (8.5.3) et ne se réfère à un objet implicite paramètre de non-fonction membre statique déclarée sans ref-qualificatif, et S1 lie référence rvalue à une rvalue et S2 lie une lvalue de référence.

Une conversion de la séquence ne peut pas être formée si elle nécessite une liaison référence rvalue à une lvalue, la spec dit à 13.3.3.1.4p3. Si vous regardez comment la référence de la liaison fonctionne à 8.5.3p5 dernière balle, il va créer un temporaire (je pense qu'ils voulaient dire rvalue temporaire) de type char const* à partir de la matrice de lvalue et lier la référence que temporaire. À cet effet, je pense que (1) est mieux que (2). De même pour (1) contre (3), bien que nous n'aurions pas besoin de cela, car (3) est un modèle de sorte à égalité, nous choisirions (1) de nouveau.

En n3225, ils ont changé la référence des règles contraignantes afin que les références rvalue peut se lier à l'initialiseur expressions qui sont lvalues, tant que la référence soit lié à une rvalue (peut-être créé par la conversion de l'initialiseur correctement avant). Cela pourrait influencer le traitement par Visual C++, qui peut ne pas être à jour ici.

Je ne suis pas sûr de clang. Même si il serait ignorer (1), alors qu'il finirait dans une égalité entre (2) et (3), et aurait besoin de choisir (2) parce que c'est un non-modèle.


Je pense que 8.5.3p5 dernier point est source de confusion car il est dit "dans le cas Contraire temporaire de type...". Il n'est pas clair si le temporaire est considéré comme une lvalue ou comme une rvalue par 13.3.3.1.4p3, ce qui signifie que je ne suis pas sûr de savoir comment les points suivants devraient vraiment se comporter selon les mots exacts de la spec

void f(int &);
void f(int &&);

int main() {
  int n = 0;
  f(n);
}

Si nous supposons que le temporaire est considérée comme une rvalue par l'article 13, puis nous lier une rvalue ref à une rvalue dans la seconde fonction et une lvalue dans la première. À cet effet, nous allons choisir la deuxième fonction, et ensuite obtenir un diagnostic de 8,5.3p5 dernier point, car T1 et T2 sont des références relatives. Si nous supposons que le temporaire est considérée comme une lvalue par l'article 13, puis le suivant ne marche pas

void f(int &&);
int main() {
  f(0);
}

Parce que nous lient une rvalue ref à une lvalue qui, par la clause 13 fera la fonction non-viable. Et si nous interpréter "de la liaison à une rvalue ref à une lvalue" pour se référer à l'initialiseur d'expression à la place de l'expression finale lié à l', nous n'accepterons pas les suivants

void f(float &&);
int main() {
  int n = 0;
  f(n);
}

Ceci, toutefois, est valable à compter de n3225. Il semble donc y avoir une certaine confusion - j'ai envoyé un DR à la commission à ce sujet.

4voto

Ben Voigt Points 151460

Je demande que la #3 est la fonction choisie par un compilateur conforme.

(1) est meilleure que (2), parce que "la Norme de conversion de la séquence S1 est un meilleur taux de conversion de la séquence de conversion standard de la séquence S2 si S1 et S2 sont référence des liaisons (8.5.3) et ne se réfère à un objet implicite paramètre de non-fonction membre statique déclarée sans ref-qualificatif, et S1 lie référence rvalue à une rvalue et S2 lie une lvalue de référence."

(3) est meilleure que les deux (1) et (2) parce que c'est une identité de conversion (les autres sont en correspondance exacte des conversions) et "Standard de conversion de la séquence S1 est un meilleur taux de conversion de la séquence de conversion standard de la séquence S2 si S1 est un bon sous-suite de S2 (en comparant la conversion des séquences dans la forme canonique définie par 13.3.3.1.1, à l'exclusion de toute Lvalue de Transformation; l'identité de la conversion de la séquence est considérée comme une sous-suite de la non-identité de la conversion de la séquence)"

Modèle vs non-modèle est prise en compte uniquement lorsque ni de conversion, c'est mieux "ou, si ce n'est que..."

curieusement cependant, Comeau préfère (2) sur (3). Ce test ne peut pas compiler:

#include <cstddef>
#include <cstdio>

// (1) removed because Comeau doesn't support rvalue-references yet
char f(char const* const&) { std::puts("char const* const&"); return 0; } // (2)

template <std::size_t N>
int f(char const (&)[N])  { std::puts("char const(&)[N]"); return 0; } // (3)

int main()
{
    const char data[] = "a";
    switch (0) {
       case sizeof(char):
           break;
       case sizeof(f(data)):
           break;
    }
}

2voto

Ben Voigt Points 151460

C'est un wiki de la communauté réponse pour la collecte des extraits de la norme (projet de 3225).

section 13.3.3 "plus viable de la fonction" [over.match.best]

  1. Définir l'ICSi(F) comme suit:

    • si F est une fonction membre statique, ICS1(F) est définie de telle façon que ICS1(F) est ni meilleure ni pire que ICS1(G) pour toute fonction G, et, symétriquement, ICS1(G) est ni meilleure ni pire que ICS1(F); sinon,

    • laissez-ICSi(F) désigne la conversion implicite de la séquence qui convertit la i-ème argument dans la liste de la type de la i-ème paramètre de viable fonction F. 13.3.3.1 définit la conversion implicite de séquences et de 13.3.3.2 définit ce que cela signifie pour une conversion implicite de la séquence à être un meilleur taux de conversion de la séquence ou pire de conversion de la séquence que l'autre.

    Compte tenu de ces définitions, une solution viable fonction F1 correspond à une meilleure fonction qu'une autre solution pour la fonction F2 si tous les arguments que j', l'ICSi(F1) n'est pas une aggravation de la conversion de la séquence que l'ICSi(F2), puis

    • pour certains argument j, ICSj(F1) est un meilleur taux de conversion de la séquence de ICSj(F2)

    ou, si ce n'est que,

    • le contexte est une initialisation par conversion définie par l'utilisateur (voir 8.5, 13.3.1.5, et 13.3.1.6) et le standard de conversion de la séquence, à partir du type de retour d' F1 pour le type de destination (c'est à dire, le type de l'entité en cours d'initialisation) est un meilleur taux de conversion de la séquence de la conversion standard de la séquence du type de retour d' F2 pour le type de destination

    ou, si ce n'est que,

    • F1 est un non-modèle de la fonction et de l' F2 est un modèle de fonction de la spécialisation

    ou, si ce n'est que,

    • F1 et F2 sont fonction des spécialisations de modèle, et le modèle de fonction pour F1 est plus spécialisée que le modèle pour l' F2 selon l'partielle de la commande de règles décrites dans 14.5.6.2.
  2. Si il y a exactement une solution de fonction qui est une meilleure fonction que tous les autres viable, alors il est celui qui est sélectionné par la résolution de surcharge; sinon, l'appel est mal formé.

section 13.3.3.1.4 Référence de "liaison" [over.ics.ref]

  1. Lorsqu'un paramètre de type de référence se lie directement (8.5.3) à un argument d'expression, la conversion implicite la séquence de l'identité de la conversion, à moins que l'argument de l'expression a un type qui est une classe dérivée de la type de paramètre, dans ce cas la conversion implicite de la séquence est un dérivé de la base de conversion (13.3.3.1). Si le paramètre se lie directement à la suite de l'application de la fonction de conversion à la l'argument de l'expression, de la conversion implicite de la séquence est définie par l'utilisateur de conversion de la séquence (13.3.3.1.2), avec la deuxième norme de conversion de la séquence, soit une identité de la conversion ou, si la fonction de conversion retourne une entité d'un type qui est un dérivé de la classe du type de paramètre, un dérivé de la base de la Conversion.

  2. Lorsqu'un paramètre de type de référence n'est pas lié directement à un argument d'expression, la conversion de la séquence est celui nécessaire à la conversion de l'expression d'argument pour le type sous-jacent de référence selon pour 13.3.3.1. Sur le plan conceptuel, cette conversion de la séquence correspond à la copie de l'initialisation d'un temporaire de la le type sous-jacent avec l'argument de l'expression. Aucune différence dans le niveau supérieur de cv-qualification est subsumé par l'initialisation de lui-même et ne constitue pas une conversion.

section 13.3.3.2 "le Classement de la conversion implicite séquences" [over.ics.rank]

  1. 13.3.3.2 définit partielle de la commande de conversion implicite des séquences sur la base des relations meilleur taux de conversion la séquence et le meilleur taux de conversion. Si une conversion implicite de la séquence de S1 est défini par les présentes règles pour être un meilleur la conversion de la séquence de S2, puis c'est aussi le cas, S2 est une aggravation de la conversion de la séquence de S1. Si la conversion de la séquence de S1 n'est ni meilleure que ni pire que la conversion de la séquence de S2, S1 et S2 sont dit être impossible à distinguer de conversion de séquences.

  2. Lorsque l'on compare les formes de base de la conversion implicite de séquences (tel que défini dans 13.3.3.1)

    • une conversion standard de la séquence (13.3.3.1.1) est un meilleur taux de conversion à une séquence définie par l'utilisateur pour la conversion de la séquence ou des points de suspension de la conversion de la séquence, et

    • une conversion définie par l'utilisateur de la séquence (13.3.3.1.2) est un meilleur taux de conversion de la séquence de points de suspension de la conversion de la séquence (13.3.3.1.3).

  3. Deux conversion implicite des séquences de la même forme sont indissociables de conversion de séquences, à moins que l'un des les règles suivantes s'appliquent:

    • De conversion Standard de la séquence de S1 est un meilleur taux de conversion de la séquence de conversion standard de la séquence de S2 si

      • S1 est un bon sous-suite de S2 (en comparant la conversion des séquences dans la forme canonique définie par 13.3.3.1.1, à l'exclusion de toute Lvalue de Transformation; l'identité de la conversion de la séquence est considérée comme une sous-suite de la non-identité de la conversion de la séquence)

      ou, si ce n'est que,

      • le rang de l' S1 est mieux que le rang de S2ou S1 et S2 ont le même rang et se distinguent par les règles énoncées dans le paragraphe ci-dessous

      ou, si ce n'est que,

      • S1 et S2 ne diffèrent que dans leur qualification de conversion et le rendement des types similaires T1 et T2 (4.4), respectivement, et le cv-qualification de signature de type T1 est un sous-ensemble propre de la cv-qualification de signature de type T2.

      ou, si ce n'est que,

      • S1 et S2 sont référence des liaisons (8.5.3) et ne se réfère à un objet implicite paramètre d'une non-membre statique de la fonction déclarée sans ref-qualificatif, et S1 lie référence rvalue à une rvalue et S2 lie une lvalue de référence.

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