2008-10-12 5 views
0

Supposons que j'ai un modèle de fonction comme ceci:Le fait de contraindre la classe de modèle avec l'opérateur T * en passant comme argument T * d'un modèle de fonction

template<class T> 
inline 
void 
doStuff(T* arr) 
{ 
    // stuff that needs to use sizeof(T) 
} 

Puis dans un autre .h FILEE J'ai une classe de modèle Foo qui a:

public: operator T*() const; 

Maintenant, je réalise que ce sont des Ts différents. Mais si j'ai une variable Foo<Bar> f sur la pile, la seule façon de le contraindre à n'importe quel type de pointeur serait d'appeler operator T*(). Pourtant, si appelez doStuff(f), GCC se plaint que doStuff ne peut pas prendre Foo<Bar> au lieu d'utiliser automatiquement l'opérateur T*() pour contraindre à Bar*, puis en spécialisant le modèle de fonction avec Bar comme T.

Y at-il quelque chose que je peux faire pour que cela fonctionne avec deux modèles? Ou bien l'argument de la fonction template doit-il être un vrai type de pointeur ou bien la classe template avec l'opérateur de coercition doit-elle être passée à une fonction non-template?

Répondre

3

GCC est correct. Dans les arguments de modèle, seules les correspondances exactes sont prises en compte, les conversions de type ne le sont pas. C'est parce que sinon un nombre infini (ou au moins exponentiel) de conversions pourrait devoir être considéré.

Si Foo < T> est le seul autre modèle que vous allez courir pour, la meilleure solution serait d'ajouter:

template<typename T> inline void doStuff(const Foo<T>& arr) { 
    doStuff(static_cast<T*>(arr)); 
} 

Si vous rencontrez ce problème avec beaucoup de modèles , celui-ci doit fixer:

#include <boost/type_traits/is_convertible.hpp> 
#include <boost/utility/enable_if.hpp> 
template<template <typename> class T, typename U> inline typename boost::enable_if<typename boost::is_convertible<T<U>, U*>::type>::type doStuff(const T<U>& arr) { 
    doStuff(static_cast<U*>(arr)); 
} 

il est un peu bavard mais ;-)

-1

Je ne sais pas pourquoi la conversion ne fonctionne pas, mais vous pouvez utiliser une surcharge pour résoudre le problème


template 
inline 
void 
doStuff(T& arrRef) 
{ 
    doStuff(&arrRef); 
} 
+0

Le déréférencement d'une référence est en général un mauvais style. Je sais que les hacks ont leur valeur, mais seulement utilisé avec parcimonie. –

+0

En outre, il est simplement incorrect. Syntaxiquement parce que vous n'avez pas défini T nulle part, sémantiquement car Foo .operator &() ne retournera pas un T * mais un Foo *. –

-1

Eh bien, T * est pas un type distinct de T dans le sens que vous pensez qu'il est. Le pointeur est un qualificateur de type. Je ne suis pas sûr de ce que la norme en dit, mais je dirais que comme la variable est déjà de type T, elle n'essaie pas de la convertir à nouveau. Si vous voulez faire un truc personnalisé pour obtenir un pointeur, surchargez l'opérateur &.

+0

T * est un type distinct de T dans le sens où tout le monde pense qu'il est ... –

+0

Vous ne voulez vraiment pas surcharger l'opérateur &(). Voir les meilleures pratiques de google pour des raisons pourquoi. –

2

cela pourrait être la peine d'essayer:

Je pense que cela va amener le compilateur à s'attendre à ce que T * soit Bar *, puis utiliser l'opérateur T *() de Foo pour effectuer la conversion, mais je ne peux pas dire que je l'ai essayé.

+0

C'est correct. Le compilateur se plaint car la déduction d'argument de modèle échoue. Une fois que vous avez fourni l'argument, il n'y a pas de TAD. À ce stade, le compilateur connaît à la fois le type cible et le type de destination pour la séquence de conversion. – MSalters

0

L'idée de Leon est probablement la meilleure. Mais à la rigueur, vous pouvez également appeler l'opérateur de distribution explicitement:

doStuff(static_cast<Bar*>(f)); 
Questions connexes