Question

Il y a quelque temps je confus par le comportement suivant de peu de code quand je voulais écrire un trait is_callable<F, Args...>. Les surcharges n'appeler des fonctions acceptant des arguments par ref non const, non? Pourquoi ne pas rejeter dans ce qui suit parce que le constructeur veut un Test&? Je m'y attendais à prendre f(int)!

struct Test {
  Test() { }

  // I want Test not be copyable from rvalues!
  Test(Test&) { }

  // But it's convertible to int
  operator int() { return 0; }
};

void f(int) { }
void f(Test) { }

struct WorksFine { };
struct Slurper { Slurper(WorksFine&) { } };
struct Eater { Eater(WorksFine) { } };

void g(Slurper) { }
void g(Eater) { } // chooses this, as expected

int main() {
  // Error, why?
  f(Test());

  // But this works, why?
  g(WorksFine());
}

Message d'erreur est

m.cpp: In function 'int main()':
m.cpp:33:11: error: no matching function for call to 'Test::Test(Test)'
m.cpp:5:3: note: candidates are: Test::Test(Test&)
m.cpp:2:3: note:                 Test::Test()
m.cpp:33:11: error:   initializing argument 1 of 'void f(Test)'

Pouvez-vous s'il vous plaît expliquer pourquoi on travaille, mais l'autre ne fonctionne pas?

Était-ce utile?

La solution

résolution de surcharge prend la fonction qui est la plus proche de l'argument fourni. Vous avez fourni un test. Aucune conversion nécessaire - conversion d'identité utilisée. Ainsi choisit de résolution de la fonction f (Test). Test ne peut être copié à partir rvalue, qui vous avez fourni, mais la résolution de surcharge a déjà réussi ... conversion en int est jamais vérifié.

g(Eater) est choisi parce que les types ne correspondent pas exactement, la conversion d'identité est pas utilisé, et le compilateur doit trouver une routine de conversion qui fonctionne. g(Slurper) ne pas parce que vous ne pouvez pas faire un à partir de l'argument fourni.

"Pourquoi pas celui-ci Fail: struct A { operator int(); }; void f(A&); void f(int); void g() { f(A()); }"

Parce que f (A &) ne soit pas une surcharge viable pour l'argument fourni. Dans ce cas, le paramètre est une référence et le fait que temps ne se lient pas à la non-const est autorisé à effectuer la résolution. Dans ce cas, il fait et la cette version de la fonction devient un non-candidat, ne laissant que le seul et cela fonctionne.

Autres conseils

Fondamentalement, pour la résolution de surcharge, il est supposé que l'objet de type A peut être converti en un objet de type A, indépendamment de toute cv-qualification sur l'un des deux.

Du projet n1905:

13.3.3.1: Overloading.Overload Resolution.Best Viable Function.Implicit Conversion des séquences

  

6 Lorsque le type de paramètre est une référence non , les modèles de séquence de conversion implicites une copie-initialisation du paramètre à partir de l'expression d'argument. La séquence de conversion implicite est celle requise pour convertir l'argument   expression d'une rvalue du type du paramètre. [ Note : lorsque le paramètre a un type de classe, c'est un concept   conversion définie aux fins de la clause 13; l'initialisation effective est définie en termes de constructeurs et n'a pas   une conversion. - end note ] Toute différence de cv-qualification de haut niveau est subsumé par l'initialisation lui-même et fait   constituent pas une conversion [ Exemple :. un paramètre de type A peut être initialisé à partir d'un argument de type const A.   La séquence de conversion implicite pour ce cas est la séquence ayant une identité; il ne contient pas de « conversion » de A à const   A. - exemple de fin ] Lorsque le paramètre a un type de classe et l'expression d'argument a le même type, l'implicite   la séquence de conversion est une conversion d'identité . [...]

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top