2011-03-28 3 views
6

J'ai une classe A:conversion implicite à un objet C++ modèle

template <typename T, int I> struct A {}; 

et classe B. Je voudrais de type B objet à convertir implicitement à A quand donné comme arguments de la fonction. B ressemble à ceci:

template <typename T> 
struct B { 
    operator A<T,0> &() const { return *new A<T,0>(); } 
}; 

Cependant, mon test (ci-dessous) échoue avec GCC 4.5, ce qui donne l'erreur: aucune fonction de mise en correspondance pour l'appel à 'test (B &)' Où vais-je pas ici? Est-ce que d'autres compilateurs rejettent aussi cela?

template <typename T, int I> 
void test(A<T,I> &a) { delete &a; } 

int main(int argc, char *argv[]) 
{ 
    B<int> b; 
    test(b); 
    return 0; 
} 

p.s. J'ai maintenant mis ma propre solution dans une réponse ci-dessous.

+0

Je tiens à signaler la fuite de mémoire, mais il semble que cela a été tout simplement mis en place pour mettre en valeur la question, je ne vais pas. Je vais upvote à la place. :-) – James

+0

classe? -------- –

+0

Merci James :) Correction. – user2023370

Répondre

2

Si vous voulez une conversion implicite de B à A vous devez soit:

Un opérateur coulé sur B:

operator A<T,0>(); 

ou un constructeur qui prend une référence B:

A(const B& other); 

ou B tirer de A. Qu'est-ce que vous avez déclaré:

operator A<T,0> &() const; 

ressemble un peu à une adresse mal déclarée de surcharge.

Cependant, puisque test() prend une référence (et non const), l'option d'opérateur de conversion ne fonctionnera pas.

C'est ce que je l'ai testé:

template <typename T, int I> struct A {}; 

template <typename T> 
struct B { 
    //operator A<T,0> &() const { return *new A<T,0>(); } 

    template< int I > 
    operator A<T, I>() const { return A< T, 0 >(); } 
}; 

template <typename T, int I> 
void test(A<T,I> &) { } 

int f() 
{ 
    B<int> b; 

    A<int, 0> a(b); 
    test(a); // <-- Success 

    test(b); // <-- Failure, "could not deduce template argument" 
    return 0; 
} 

Conversion à A en initialisant une variable locale fonctionne très bien.

+0

Pour paraphraser manuellement: Puisque test() prend une référence non-const à un A, vous devez lui passer quelque chose avec le type A qu'il peut changer. Puisque B n'est pas dérivé de A, rien de ce que vous pouvez déclarer dans B ne vous permettra de le faire implicitement. – RobH

+0

Je ne l'ai jamais fait, mais je pense qu'il est possible de déclarer un opérateur de conversion qui retourne 'A <...> &' si typedef est utilisé. Bien sûr, pour que cela soit utile, B doit avoir une instance de A non-const dans lui. – Arkadiy

3

Non lié à votre problème, mais return *new A<T,0>(); est faux car fuit la mémoire invite une fuite de mémoire. Vous devez pas utiliser new ici. return A<T, 0>(); et en supprimant la référence du type de retour fonctionne très bien et ne fuit pas la mémoire. Etes-vous sûr de vouloir réellement une telle conversion implicite ici?

+0

Merci Konrad. Je crois que cela me forcerait à faire accepter par test uniquement les arguments de référence const? – user2023370

+0

'test' prend son paramètre par référence non-const, ce qui est encore plus déroutant (s'il veut modifier son paramètre). –

+0

@ user643722 True. Vous pourriez le surcharger cependant. –

1

Cela ressemble à un moyen parfait de vous confondre ou d'entretenir un autre, ou pire, d'appeler une fonction en utilisant le mauvais argument parce que la conversion implicite le permet. Au lieu de cela, considérons un modèle make_A comme std::make_pair pour afficher explicitement votre intention sur le site d'appel.

+0

Merci Mark. Le code est généré automatiquement et, une fois la solution trouvée, ne sera pas modifié par les utilisateurs finaux. – user2023370

+0

@ user643722 Alors c'est encore plus une raison pour utiliser l'appel explicite puisqu'il est généré automatiquement. On peut supposer que les humains doivent encore lire le code. –

0

Cela échoue également dans VC++. Pour le faire fonctionner, ajouter cette méthode:

template <typename T> 
void test(B<T> &b) 
{ 
    test(static_cast< A<T,0>& > (b)); 
} 

Cela prendra une B réelle, faire explicitement la conversion (via static_cast), puis appelez test en utilisant la A nous venons de faire.

Je reçois des erreurs quand je l'exécute. J'espère que ce n'est qu'un exemple de code, et que vous ne faites pas delete &a dans votre code actuel. RobH vous a donné un meilleur opérateur de conversion et évite le désordre du pointeur.

+0

Vous devriez probablement le convertir en une référence: 'static_cast &> (b)', sinon une copie est faite, que le test essaie de supprimer. – UncleBens

+0

D'oh! Oui, ça résout mon problème. Bonne prise, @UncleBens – Tim

1

Fournir une surcharge de test comme le suivant permettra d'écrire test(b) comme dans la question.
Par exemple:

template <typename T> 
void test(B<T> const &b) { 
    test(static_cast< A<T,0>& >(b)); 
} 

test(b); // caller 

Si cette surcharge n'est pas autorisé, mais vous êtes autorisé à modifier la définition de B, que diriez-vous fournir la fonction membre qui retourne A comme suit, au lieu de la fonction de conversion?

template <typename T> 
struct B { 
    A<T,0> &to_A() const { return *new A<T,0>(); } 
}; 

test(b.to_A()); 

Si vous n'êtes pas autorisé à modifier la définition de B, le to_A ci-dessus sera une fonction libre comme la suivante au lieu de la fonction membre:

template <typename T> 
A<T,0> &to_A(B<T> const &b) { 
    return static_cast< A<T,0>& >(b); 
} 

test(to_A(b)); 

Hope this helps

0

Je me suis contenté d'utiliser l'opérateur de conversion de valeur par passage suggéré par Konrad; l'appel de fonction de modèle explicite de Let_Me_Be; et j'ai saupoudré un peu de magie C++ 0x en haut: une référence rvalue sur le paramètre à tester. (Ou, devrait-il être 2011 C++ maintenant?)

template <typename T, int I> struct A { int x; }; 

template <typename T> 
struct B { 
    operator A<T,0>() const { return A<T,0>(); } 
}; 

template <typename T, int I> 
void test(A<T,I> &&a) { a.x=7; printf("%d\n", x); } 

int main(int argc, char *argv[]) 
{ 
    B<int> b; 
    test<int,0>(b); 
    return 0; 
} 
Questions connexes