Considérons le modèle de classe "X" suivant et ses spécialisations partielles.
template <class ...Types>
struct X {}; // #1
template <class T1>
struct X<T1> {}; // #2
template <class T1, class ...Types>
struct X<T1, Types...> {}; // #3
X<int> x; // #2 or #3 ?
Je soupçonne que X<int> est ambiguë. Il l'est parce que :
Il est évident que les numéros 2 et 3 sont plus spécialisés que le numéro 1, les numéros 2 et 3 sont maintenant comparés. Selon 14.5.5.2, considérons lequel des #2' et #3' suivants est le plus spécialisé.
template <class T1>
void f(X<T1>); // #2'
template <class T1, class ...Types>
void f(X<T1, Types...>); // #3'
Selon 14.8.2.4, la première étape est la déduction du modèle d'argument en utilisant #2' comme modèle d'argument et #3' comme modèle de paramètre. Étant donné que le seul type d'argument est X<A1>, le T1 déduit est A1, et Types est vide.
A = X<A1>, P = X<T1, Types...> => T1 = A1, Types = {}
La deuxième étape est effectuée en utilisant le modèle #3' comme modèle d'argument et le modèle #2' comme modèle de paramètre. Étant donné que le seul type d'argument est X<A1, Args...>, selon 14.8.2.5/9 (notez que ce paragraphe a été récemment révisé par N3281), Args est simplement ignoré, le T1 déduit est A1 et la déduction d'argument réussit.
A = X<A1, Args...>, P = X<T1> => T1 = A1 (Args is ignored)
Enfin, les déductions d'arguments bidirectionnels ont réussi. Donc #2 est tout aussi spécialisé que #3. En conclusion, X<int> est ambiguë.
Ma question est la suivante : "Mon interprétation est-elle correcte ?"
Si cette interprétation est correcte, la définition de 'std::common_type' dans 20.9.7.6/3 est inappropriée.
template <class ...T>
struct common_type; // #1
template <class T>
struct common_type<T> // #2
{
typedef T type;
};
template <class T, class U>
struct common_type<T, U> // #3
{
typedef
decltype(true ? declval<T>() : declval<U>())
type;
};
template <class T, class U, class ...V>
struct common_type<T, U, V...> // #4
{
typedef typename
common_type<typename common_type<T, U>::type, V...>::type
type;
};
Lorsque common_type<A, B> est utilisé, les points 3 et 4 sont ambigus.
Note : sur le premier exemple, GCC 4.7.0 (snapshot) et Clang 3.0 sélectionnent #2. Cependant, ces compilateurs sont si peu fiables qu'ils ne suivent pas les autres changements de N3281.
1 votes
Il semble que vous ayez raison. Un paquet de paramètres vide ne devrait pas affecter l'ordre partiel. gcc semble ignorer cela et placer un modèle variadique plus bas dans la liste, toutes choses étant égales par ailleurs. Par exemple, il compile un exemple à 14.5.6.2/5 qui est explicitement déclaré comme étant ambigu.
0 votes
La correction est généralement le sujet des tests unitaires, surtout en programmation. Cela permet de s'assurer que votre interprétation est correcte et que vous comprenez les spécifications du langage avec un haut degré de confiance, deux éléments qui peuvent être remis en question ici.
0 votes
@n.m. est ce code de quoi parlez-vous ? J'ai pris ce code de N3242 comme indiqué dans le lien Wikipedia
0 votes
14.5.6.2/5 (from N3242) "La présence d'ellipses inutilisées et d'arguments par défaut n'a pas d'effet sur l'ordre partiel des éléments suivants fonction templates" (c'est moi qui souligne). Peut-être que cela ne s'applique qu'aux modèles de fonction, alors que cette question concerne les modèles de classe ?
0 votes
@Aaron : non, celui-ci . C'est le dernier exemple de 14.5.6.2. Il compile bien que le commentaire indique clairement qu'il ne devrait pas le faire.
0 votes
@Aaron : l'ordre partiel des modèles de classe est exprimé en termes d'ordre partiel des modèles de fonction, comme décrit en 14.5.5.2. Il doit donc s'appliquer aux deux.
0 votes
Dans N3242, dans 14.5.6.2/5, ils ne disent pas que cela ne devrait pas compiler. Il semble qu'ils aient changé l'exemple dans le document que vous regardez.
0 votes
(en d'autres termes, je suis probablement en train de regarder un document obsolète, et je ne suis pas un expert en la matière de toute façon !)