J'ai simplifié votre exemple à ce qui suit:
typedef unsigned int size_t;
template <typename T>
class List
{
public:
typedef size_t size_type;
List (List const &);
List (size_type i, T const & = T());
};
typedef List<unsigned char> UCList;
class MyClass
{
public:
operator UCList const() const;
operator unsigned char() const;
};
void foo()
{
MyClass mc;
(UCList)mc;
}
Le premier point, est que la norme définit que la fonte de style C devrait utiliser la distribution de style plus approprié C++, et dans ce cas qui est static_cast
.Ainsi, la distribution est équivalente à:
static_cast<UCList> (mc);
La définition de static_cast dit:
Une expression e peut être converti explicitement à un type T en utilisant un static_cast
du formulaire static_cast<T>(e)
si la déclaration "T t(e);"
est bien formée, pour une variable temporaire inventé t (8,5)
ainsi la sémantique pour la coulée sont les mêmes que pour:
UCList tmp (mc);
De 13.3.1.3 nous obtenons l'ensemble des constructeurs de candidats que nous pouvons utiliser dans UCList
:
UCList (UCList const &) #1
UCList (size_type, T const & = T()); #2
Que se passe ensuite est à deux pas de résolution de surcharge, une pour chaque opérateur de conversion.
Conversion en # 1: Avec un type de cible de UCList const &
, la résolution de surcharge sélectionne entre les opérateurs de conversion suivants .: "operator UCList const()
" et "operator unsigned char()
". L'utilisation de unsigned char
nécessiterait une conversion utilisateur supplémentaire et n'est donc pas une fonction viable pour cette étape de surcharge. Par conséquent, la résolution de surcharge réussit et utilisera operator UCList const()
.
Conversion en # 2: Avec le type de cible size_t
. L'argument par défaut ne participe pas à la résolution de surcharge. La résolution de surcharge sélectionne à nouveau entre les opérateurs de conversion: "operator UCList const()
" et "operator unsigned char()
". Cette fois, il n'y a pas de conversion de UCList
à unsigned int
et donc ce n'est pas une fonction viable. Un unsigned char
peut être promu à size_t
et donc cette résolution de surcharge de temps réussit et utilisera "operator UCList const()
". Mais maintenant, au niveau supérieur, il existe deux étapes de résolution de surcharge séparées et indépendantes qui ont été converties avec succès de mc
à UCList
. Le résultat est donc ambigu. Pour expliquer ce dernier point, cet exemple est différent du cas de résolution de surcharge normal. Normalement, il y a un 1: la relation entre les n types d'arguments et paramètres:
void foo (char);
void foo (short);
void foo (int);
void bar() {
int i;
foo (i);
}
Ici il y a i=>char
, i=>short
et i=>int
. Ceux-ci sont comparés par résolution de surcharge et la surcharge int
est sélectionnée.
Dans le cas ci-dessus, nous avons une relation m: n. La norme décrit les règles à sélectionner pour chaque argument individuel et tous les paramètres «n», mais c'est là qu'elle se termine, elle ne spécifie pas comment nous devrions décider d'utiliser les différents arguments «m».
Espérons que cela a du sens!
MISE À JOUR:
Les deux types de syntaxe d'initialisation ici sont:
UCList t1 (mc);
UCList t2 = mc;
't1' est une initialiation directe (13.3.1.3) et tous constructeurs sont inclus dans la surcharge ensemble. C'est presque comme avoir plus d'une conversion définie par l'utilisateur. Il y a l'ensemble des constructeurs et l'ensemble des opérateurs de conversion. (c'est-à-dire m: n).
Dans le cas de « t2 » utilise la syntaxe copy-initialisation (13.3.1.4) et les règles différent:
Dans les conditions spécifiées dans 8,5, dans le cadre d'une copie de l'initialisation d'un objet de type classe, une conversion définie par l'utilisateur peut être appelée pour convertir une expression d'initialisation en type d'objet en cours d'initialisation. résolution de surcharge est utilisé pour sélectionner la conversion définie par l'utilisateur à invoquer
Dans ce cas, il est juste un à taper, UCList
, et donc il n'y a que l'ensemble de l'opérateur de conversion Surcharges à considérer, par exemple. nous ne considérons pas les autres constructeurs de UCList.
Pourquoi est-ce le cas? Je sais pertinemment que vous pouvez implicitement appeler un casting surchargé. –
Désolé, appelez explicitement. –
Pas vraiment sûr, je suppose que si vous ne dites pas explicitement que vous voulez utiliser votre opérateur (en cast), il peut utiliser d'abord l'opérateur standard à const et puis le vôtre, mais quand vous voulez explicitement utiliser le direct des conflits avec le const &, mais pas vraiment sûr. –