2009-05-15 5 views
23

Plusieurs commentaires sur une réponse récente, What other useful casts can be used in C++, suggèrent que ma compréhension des conversions C++ est défectueuse. Juste pour clarifier la question, considérez le code suivant:Conversions implicites C++

#include <string> 

struct A { 
    A(const std::string & s) {} 
}; 

void func(const A & a) { 
} 

int main() { 
    func("one");     // error 
    func(A("two"));   // ok 
    func(std::string("three")); // ok 
} 

Mon affirmation est que le premier appel de fonction est une erreur, becauuse il n'y a pas de conversion à partir d'un const char * à un A. Il y a une conversion de une chaîne à un A, mais l'utiliser impliquerait plus d'une conversion. Ma compréhension est que cela n'est pas autorisé, et cela semble être confirmé par g ++ 4.4.0 & Comeau compilateurs. Avec Comeau, je reçois l'erreur suivante:

"ComeauTest.c", line 11: error: no suitable constructor exists 
     to convert from "const char [4]" to "A" 
     func("one");     // error 

Si vous soulignez, où je me trompe, que ce soit ici ou dans la réponse initiale, de préférence en référence à la norme C++, s'il vous plaît le faire.

Et la réponse de la norme C semble être de:

At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

Merci à Abhay pour fournir le devis.

+0

Je suis désolé j'ai eu tout faux dans le commentaire à votre réponse. J'ai lu "La résolution de surcharge est utilisée pour sélectionner la conversion définie par l'utilisateur à invoquer.", Et je me suis dit "bien, alors il se résoudra à A (chaîne const &) et passera" un ", mais j'ai totalement échoué pour penser à ce que 13.3.3.1.2 dit: "Une séquence de conversion définie par l'utilisateur consiste en une séquence de conversion standard initiale suivie d'une conversion définie par l'utilisateur (12.3) suivie d'une seconde séquence de conversion standard." Mais "one" -> chaîne ne serait pas une séquence de conversion standard, mais nécessite une autre séquence de conversion définie par l'utilisateur! –

+0

Tant que je ne perds pas mes billes :-) –

+0

Bonne question! La discussion implique que 'std :: string' ne fait pas partie du langage et que les conversions vers/depuis lui sont" définies par l'utilisateur ". Au moins c'est ce que je comprends, corrigez-moi si je me trompe. Ce serait bien si la question était plus explicite à ce sujet. Le statut exact de 'std :: string' peut être clair pour les anciennes mains C++, mais n'est pas si facile à réaliser pour les personnes qui sont venues à la langue dans ce siècle. –

Répondre

12

Je pense que la réponse de sharptooth est précise. La section 12.3.4 intitulée «Conversions» de la norme C++ Standard (SC22-N-4411.pdf) indique clairement qu'une seule conversion implicite définie par l'utilisateur est autorisée.

1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

2 User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). Conversions obey the access control rules (Clause 11). Access control is applied after ambiguity resolution (3.4).

3 [ Note: See 13.3 for a discussion of the use of conversions in function calls as well as examples below. —end note ]

4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

+0

Je me sens obligé de partager pourquoi j'aime utiliser les conversions implicites dans un scénario spécifique: à savoir, quand je veux coupler une variable d'un type simple avec une classe qui effectue des fonctions connexes sur la variable. En plus de la conversion implicite, je fournis une fonction dans la classe qui retourne la valeur, de la même manière que std :: string fournit c_str(). Ensuite, vous pouvez avoir la fonctionnalité de classe supplémentaire là où vous en avez besoin, et vous pouvez aller extrêmement léger ailleurs, tout en conservant les fonctionnalités associées. – moodboom

8

C'est vrai, une seule conversion implicite est autorisée.

Deux conversions d'affilée peuvent être effectuées avec une combinaison d'un opérateur de conversion et d'un constructeur paramétré mais cela provoque une C4927 warning - "conversion illégale, plus d'une conversion définie par l'utilisateur a été implicitement appliquée" - dans VC++ pour un raison.

5

The C++ Programming Language (4e éd.). (section 18.4.3) dit que

only one level of user-defined implicit conversion is legal

que « défini par l'utilisateur » partie fait sonner comme plusieurs conversions implicites peuvent être autorisés si certains sont entre indigènes les types.

+0

+1 pour avoir cité le dernier ed. du livre de Stroustrup – mloskot

9

Comme le consensus semble l'être déjà: oui vous avez raison.

Mais comme cette question/réponses deviendra probablement le point de référence pour les conversions implicites C++ sur stackoverflow je voudrais ajouter que pour les arguments de template les règles sont différentes.

Aucune conversion implicite n'est autorisée pour les arguments utilisés pour la déduction des arguments de modèle. Cela peut sembler assez évident, mais peut néanmoins conduire à une bizarrerie subtile.

cas au point, std :: string opérateurs addition

std::string s; 
s += 67; // (1) 
s = s + 67; // (2) 

(1) compile et fonctionne très bien, operator+= est une fonction membre, le paramètre de caractère de modèle est déjà déduit par instanciation std::string pour s (à char). Ainsi, les conversions implicites sont autorisées (int ->char), ce qui donne s l'équivalent char de 67, par ex.en ASCII cela deviendrait « C »

(2) donne une erreur de compilation comme operator+ est déclaré en fonction libre et ici l'argument de caractère de modèle est utilisé dans la déduction.

Questions connexes